diff --git a/requirements.txt b/requirements.txt index 4f89c91e0..c76dcbeef 100644 --- a/requirements.txt +++ b/requirements.txt @@ -24,7 +24,6 @@ drf-spectacular==0.28.0 firebase-admin==6.5.0 flower==2.0.1 gunicorn[gevent]==22.0.0 -hexbytes==0.3.1 hiredis==3.0.0 packaging>=21.0 pika==1.3.2 @@ -33,5 +32,5 @@ psycogreen==1.0.2 psycopg[binary]==3.2.3 redis==5.2.1 requests==2.32.3 -safe-eth-py[django]==6.4.0 -web3==6.20.2 +safe-eth-py[django]==7.0.0 +web3==7.8.0 diff --git a/safe_transaction_service/account_abstraction/admin.py b/safe_transaction_service/account_abstraction/admin.py index c57374191..4e2dec530 100644 --- a/safe_transaction_service/account_abstraction/admin.py +++ b/safe_transaction_service/account_abstraction/admin.py @@ -3,6 +3,7 @@ from eth_typing import ChecksumAddress from hexbytes import HexBytes from safe_eth.eth.django.admin import AdvancedAdminSearchMixin +from safe_eth.util.util import to_0x_hex_str from .models import SafeOperation, UserOperation, UserOperationReceipt @@ -42,11 +43,11 @@ class ForeignClassToUserOperationAdmin(AdvancedAdminSearchMixin, admin.ModelAdmi @admin.display() def ethereum_tx(self, obj: ForeignClassToUserOperationType) -> str: - return HexBytes(obj.user_operation.ethereum_tx.tx_hash).hex() + return to_0x_hex_str(HexBytes(obj.user_operation.ethereum_tx.tx_hash)) @admin.display() def user_operation_hash(self, obj: ForeignClassToUserOperationType) -> str: - return HexBytes(obj.user_operation.hash).hex() + return to_0x_hex_str(HexBytes(obj.user_operation.hash)) @admin.display() def user_operation_sender( diff --git a/safe_transaction_service/account_abstraction/management/commands/reindex_4337.py b/safe_transaction_service/account_abstraction/management/commands/reindex_4337.py index 7213b3c9c..2a90568fd 100644 --- a/safe_transaction_service/account_abstraction/management/commands/reindex_4337.py +++ b/safe_transaction_service/account_abstraction/management/commands/reindex_4337.py @@ -4,6 +4,7 @@ from eth_typing import ChecksumAddress from safe_eth.eth.utils import fast_to_checksum_address +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.history.models import EthereumTx @@ -39,7 +40,7 @@ def reindex( self, addresses: Optional[Sequence[ChecksumAddress]], ) -> None: - topic = USER_OPERATION_EVENT_TOPIC.hex() + topic = to_0x_hex_str(USER_OPERATION_EVENT_TOPIC) aa_processor_service = get_aa_processor_service() processed_user_operations = 0 for tx in EthereumTx.objects.account_abstraction_txs(): diff --git a/safe_transaction_service/account_abstraction/models.py b/safe_transaction_service/account_abstraction/models.py index 1a16bce11..d79b827c4 100644 --- a/safe_transaction_service/account_abstraction/models.py +++ b/safe_transaction_service/account_abstraction/models.py @@ -18,6 +18,7 @@ ) from safe_eth.safe.account_abstraction import SafeOperation as SafeOperationClass from safe_eth.safe.safe_signature import SafeSignatureType +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.history import models as history_models from safe_transaction_service.utils.constants import SIGNATURE_LENGTH @@ -58,7 +59,7 @@ class Meta: ] def __str__(self) -> str: - return f"{HexBytes(self.hash).hex()} UserOperation for sender={self.sender} with nonce={self.nonce}" + return f"{to_0x_hex_str(HexBytes(self.hash))} UserOperation for sender={self.sender} with nonce={self.nonce}" @cached_property def paymaster_and_data(self) -> Optional[HexBytes]: @@ -123,7 +124,7 @@ class UserOperationReceipt(models.Model): deposited = Uint256Field() def __str__(self) -> str: - return f"{HexBytes(self.user_operation_id).hex()} UserOperationReceipt" + return f"{to_0x_hex_str(HexBytes(self.user_operation_id))} UserOperationReceipt" class SafeOperationQuerySet(models.QuerySet): @@ -151,7 +152,7 @@ class SafeOperation(TimeStampedModel): module_address = EthereumAddressBinaryField(db_index=True) def __str__(self) -> str: - return f"{HexBytes(self.hash).hex()} SafeOperation for user-operation={HexBytes(self.user_operation_id).hex()}" + return f"{to_0x_hex_str(HexBytes(self.hash))} SafeOperation for user-operation={to_0x_hex_str(HexBytes(self.user_operation_id))}" def build_signature_prefix(self) -> bytes: """ @@ -217,5 +218,5 @@ class Meta: def __str__(self): return ( f"Safe Operation Confirmation of owner={self.owner} for " - f"safe-operation={HexBytes(self.safe_operation_id).hex()}" + f"safe-operation={to_0x_hex_str(HexBytes(self.safe_operation_id))}" ) diff --git a/safe_transaction_service/account_abstraction/serializers.py b/safe_transaction_service/account_abstraction/serializers.py index 569ae2128..17bdffdf9 100644 --- a/safe_transaction_service/account_abstraction/serializers.py +++ b/safe_transaction_service/account_abstraction/serializers.py @@ -15,6 +15,7 @@ from safe_eth.eth.utils import fast_keccak, fast_to_checksum_address from safe_eth.safe.account_abstraction import SafeOperation as SafeOperationClass from safe_eth.safe.safe_signature import SafeSignature, SafeSignatureType +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.utils.constants import SIGNATURE_LENGTH from safe_transaction_service.utils.ethereum import get_chain_id @@ -72,11 +73,11 @@ def _validate_signature( if owner not in safe_owners: raise ValidationError( f"Signer={owner} is not an owner. Current owners={safe_owners}. " - f"Safe-operation-hash={safe_operation_hash.hex()}" + f"Safe-operation-hash={to_0x_hex_str(safe_operation_hash)}" ) if not safe_signature.is_valid(self.ethereum_client, safe_address): raise ValidationError( - f"Signature={safe_signature.signature.hex()} for owner={owner} is not valid" + f"Signature={to_0x_hex_str(safe_signature.signature)} for owner={owner} is not valid" ) if owner in owners_processed: raise ValidationError(f"Signature for owner={owner} is duplicated") @@ -241,7 +242,7 @@ def validate(self, attrs): if SafeOperationModel.objects.filter(hash=safe_operation_hash).exists(): raise ValidationError( - f"SafeOperation with hash={safe_operation_hash.hex()} already exists" + f"SafeOperation with hash={to_0x_hex_str(safe_operation_hash)} already exists" ) safe_signatures = self._validate_signature( @@ -456,7 +457,7 @@ def get_prepared_signature(self, obj: SafeOperationModel) -> HexStr: :return: Serialized queryset """ signature = obj.build_signature() - return HexStr(HexBytes(signature).hex()) + return to_0x_hex_str(HexBytes(signature)) class SafeOperationWithUserOperationResponseSerializer(SafeOperationResponseSerializer): diff --git a/safe_transaction_service/account_abstraction/services/aa_processor_service.py b/safe_transaction_service/account_abstraction/services/aa_processor_service.py index bcb2de9fa..872900d8d 100644 --- a/safe_transaction_service/account_abstraction/services/aa_processor_service.py +++ b/safe_transaction_service/account_abstraction/services/aa_processor_service.py @@ -18,6 +18,7 @@ from safe_eth.eth.utils import fast_to_checksum_address from safe_eth.safe.account_abstraction import SafeOperation from safe_eth.safe.safe_signature import SafeSignature +from safe_eth.util.util import to_0x_hex_str from web3.types import LogReceipt from safe_transaction_service.history import models as history_models @@ -161,7 +162,7 @@ def index_safe_operation( "[%s] Cannot find ExecutionFromModuleSuccess or ExecutionFromModuleFailure " "events for user-operation-hash=%s , it seems like UserOperation was reverted", user_operation_model.sender, - user_operation.user_operation_hash.hex(), + to_0x_hex_str(user_operation.user_operation_hash), ) if user_operation_receipt.get_deployed_account(): # UserOperation `initCode` was executed but `callData` failed, so account was deployed but @@ -169,7 +170,7 @@ def index_safe_operation( logger.info( "[%s] user-operation-hash=%s was reverted but contract was deployed", user_operation_model.sender, - user_operation.user_operation_hash.hex(), + to_0x_hex_str(user_operation.user_operation_hash), ) # As `module_address` cannot be detected there's not enough data to index the SafeOperation return None @@ -195,8 +196,8 @@ def index_safe_operation( logger.debug( "[%s] safe-operation-hash=%s for user-operation-hash=%s was already indexed", user_operation_model.sender, - HexBytes(safe_operation_hash).hex(), - user_operation.user_operation_hash.hex(), + to_0x_hex_str(HexBytes(safe_operation_hash)), + to_0x_hex_str(user_operation.user_operation_hash), ) self.index_safe_operation_confirmations( HexBytes(safe_operation.signature), safe_operation_model, safe_operation @@ -214,8 +215,8 @@ def index_user_operation_receipt( :return: Tuple with ``UserOperation`` and ``UserOperationReceipt`` """ safe_address = user_operation_model.sender - user_operation_hash_hex = HexBytes(user_operation_model.hash).hex() - tx_hash = HexBytes(user_operation_model.ethereum_tx_id).hex() + user_operation_hash_hex = to_0x_hex_str(HexBytes(user_operation_model.hash)) + tx_hash = to_0x_hex_str(HexBytes(user_operation_model.ethereum_tx_id)) logger.debug( "[%s] Retrieving UserOperation Receipt with user-operation-hash=%s on tx-hash=%s", safe_address, @@ -285,7 +286,7 @@ def index_user_operation( :param ethereum_tx: Stored EthereumTx in database containing the ``UserOperation`` :return: tuple of ``UserOperationModel`` and ``UserOperation`` """ - user_operation_hash_hex = user_operation_hash.hex() + user_operation_hash_hex = to_0x_hex_str(user_operation_hash) # If the UserOperationReceipt is present, UserOperation was already processed and mined if self.is_user_operation_indexed(user_operation_hash_hex): logger.warning( diff --git a/safe_transaction_service/account_abstraction/tests/factories.py b/safe_transaction_service/account_abstraction/tests/factories.py index 20b28a4a0..720455142 100644 --- a/safe_transaction_service/account_abstraction/tests/factories.py +++ b/safe_transaction_service/account_abstraction/tests/factories.py @@ -8,6 +8,7 @@ from safe_eth.eth.constants import NULL_ADDRESS from safe_eth.eth.utils import fast_keccak_text from safe_eth.safe.safe_signature import SafeSignatureType +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.history.tests import factories as history_factories @@ -23,7 +24,9 @@ class Params: valid_after = 0 valid_until = 0 - hash = factory.Sequence(lambda n: fast_keccak_text(f"user-operation-{n}").hex()) + hash = factory.Sequence( + lambda n: to_0x_hex_str(fast_keccak_text(f"user-operation-{n}")) + ) ethereum_tx = factory.SubFactory(history_factories.EthereumTxFactory) sender = factory.LazyFunction(lambda: Account.create().address) nonce = factory.Sequence(lambda n: n) @@ -59,7 +62,9 @@ class SafeOperationFactory(DjangoModelFactory): class Meta: model = models.SafeOperation - hash = factory.Sequence(lambda n: fast_keccak_text(f"safe-operation-{n}").hex()) + hash = factory.Sequence( + lambda n: to_0x_hex_str(fast_keccak_text(f"safe-operation-{n}")) + ) user_operation = factory.SubFactory(UserOperationFactory) valid_after = factory.LazyFunction(timezone.now) valid_until = factory.LazyFunction(timezone.now) @@ -76,6 +81,6 @@ class Params: safe_operation = factory.SubFactory(SafeOperationFactory) owner = factory.LazyAttribute(lambda o: o.signing_owner.address) signature = factory.LazyAttribute( - lambda o: o.signing_owner.signHash(o.safe_operation.hash)["signature"] + lambda o: o.signing_owner.unsafe_sign_hash(o.safe_operation.hash)["signature"] ) signature_type = SafeSignatureType.EOA.value diff --git a/safe_transaction_service/account_abstraction/tests/services/test_aa_processor_service.py b/safe_transaction_service/account_abstraction/tests/services/test_aa_processor_service.py index 6f8b501f1..c5535e84c 100644 --- a/safe_transaction_service/account_abstraction/tests/services/test_aa_processor_service.py +++ b/safe_transaction_service/account_abstraction/tests/services/test_aa_processor_service.py @@ -17,6 +17,7 @@ user_operation_v07_hash, user_operation_v07_mock, ) +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.account_abstraction.services import ( get_aa_processor_service, @@ -71,7 +72,8 @@ def tearDown(self): "get_user_operation_by_hash", autospec=True, return_value=UserOperationClass.from_bundler_response( - safe_4337_user_operation_hash_mock.hex(), user_operation_mock["result"] + to_0x_hex_str(safe_4337_user_operation_hash_mock), + user_operation_mock["result"], ), ) @mock.patch.object( @@ -97,10 +99,10 @@ def test_process_aa_transaction( user_operation_confirmation_model = SafeOperationConfirmationModel.objects.get() self.assertEqual( - user_operation_model.hash, aa_expected_user_operation_hash.hex() + user_operation_model.hash, to_0x_hex_str(aa_expected_user_operation_hash) ) self.assertEqual( - safe_operation_model.hash, aa_expected_safe_operation_hash.hex() + safe_operation_model.hash, to_0x_hex_str(aa_expected_safe_operation_hash) ) self.assertEqual(user_operation_receipt_model.deposited, 759940285250436) self.assertEqual( @@ -128,7 +130,8 @@ def test_process_aa_transaction( "get_user_operation_by_hash", autospec=True, return_value=UserOperationClass.from_bundler_response( - user_operation_v07_hash.hex(), user_operation_v07_mock["result"] + to_0x_hex_str(user_operation_v07_hash), + user_operation_v07_mock["result"], ), ) @mock.patch.object( diff --git a/safe_transaction_service/account_abstraction/tests/test_models.py b/safe_transaction_service/account_abstraction/tests/test_models.py index 3f41c08de..e0d8a1d53 100644 --- a/safe_transaction_service/account_abstraction/tests/test_models.py +++ b/safe_transaction_service/account_abstraction/tests/test_models.py @@ -8,6 +8,7 @@ user_operation_mock, ) from safe_eth.safe.account_abstraction import SafeOperation as SafeOperationClass +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.history.tests import factories as history_factories @@ -20,7 +21,8 @@ class TestModels(TestCase): def test_user_operation(self): expected_user_operation_hash = safe_4337_user_operation_hash_mock expected_user_operation = UserOperationClass.from_bundler_response( - expected_user_operation_hash.hex(), user_operation_mock["result"] + to_0x_hex_str(expected_user_operation_hash), + user_operation_mock["result"], ) expected_safe_operation = SafeOperationClass.from_user_operation( expected_user_operation diff --git a/safe_transaction_service/account_abstraction/tests/test_views.py b/safe_transaction_service/account_abstraction/tests/test_views.py index 0052812f8..ee4820572 100644 --- a/safe_transaction_service/account_abstraction/tests/test_views.py +++ b/safe_transaction_service/account_abstraction/tests/test_views.py @@ -28,6 +28,7 @@ from safe_eth.safe.proxy_factory import ProxyFactoryV141 from safe_eth.safe.safe_signature import SafeSignatureEOA, SafeSignatureType from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.utils.utils import datetime_to_str @@ -94,7 +95,7 @@ def test_safe_operation_view(self): "validUntil": datetime_to_str(safe_operation.valid_until), "moduleAddress": safe_operation.module_address, "confirmations": [], - "preparedSignature": "0x" + safe_operation.build_signature_prefix().hex(), + "preparedSignature": to_0x_hex_str(safe_operation.build_signature_prefix()), } self.assertDictEqual( response.json(), @@ -111,19 +112,16 @@ def test_safe_operation_view(self): ) ) self.assertEqual(response.status_code, status.HTTP_200_OK) - expected["preparedSignature"] = ( - "0x" - + ( - safe_operation.build_signature_prefix() - + safe_operation_confirmation.signature - ).hex() + expected["preparedSignature"] = to_0x_hex_str( + safe_operation.build_signature_prefix() + + safe_operation_confirmation.signature ) expected["confirmations"] = [ { "created": datetime_to_str(safe_operation_confirmation.created), "modified": datetime_to_str(safe_operation_confirmation.modified), "owner": safe_operation_confirmation.owner, - "signature": safe_operation_confirmation.signature.hex(), + "signature": to_0x_hex_str(safe_operation_confirmation.signature), "signatureType": "EOA", } ] @@ -180,7 +178,7 @@ def test_safe_operations_view(self): "validUntil": datetime_to_str(safe_operation.valid_until), "moduleAddress": safe_operation.module_address, "confirmations": [], - "preparedSignature": "0x" + safe_operation.build_signature_prefix().hex(), + "preparedSignature": to_0x_hex_str(safe_operation.build_signature_prefix()), } self.assertDictEqual( response.json(), @@ -205,19 +203,16 @@ def test_safe_operations_view(self): reverse("v1:account_abstraction:safe-operations", args=(safe_address,)) ) self.assertEqual(response.status_code, status.HTTP_200_OK) - expected["preparedSignature"] = ( - "0x" - + ( - safe_operation.build_signature_prefix() - + safe_operation_confirmation.signature - ).hex() + expected["preparedSignature"] = to_0x_hex_str( + safe_operation.build_signature_prefix() + + safe_operation_confirmation.signature ) expected["confirmations"] = [ { "created": datetime_to_str(safe_operation_confirmation.created), "modified": datetime_to_str(safe_operation_confirmation.modified), "owner": safe_operation_confirmation.owner, - "signature": safe_operation_confirmation.signature.hex(), + "signature": to_0x_hex_str(safe_operation_confirmation.signature), "signatureType": "EOA", } ] @@ -286,7 +281,7 @@ def test_safe_operation_create_view( user_operation_hash = safe_4337_user_operation_hash_mock user_operation = UserOperationClass.from_bundler_response( - user_operation_hash.hex(), user_operation_mock["result"] + to_0x_hex_str(user_operation_hash), user_operation_mock["result"] ) safe_operation = SafeOperationClass.from_user_operation(user_operation) @@ -299,12 +294,14 @@ def test_safe_operation_create_view( ), ) - signature = account.signHash(safe_operation_hash)["signature"].hex() + signature = to_0x_hex_str( + account.unsafe_sign_hash(safe_operation_hash)["signature"] + ) get_owners_mock.return_value = [] data = { "nonce": safe_operation.nonce, - "init_code": user_operation.init_code.hex(), - "call_data": user_operation.call_data.hex(), + "init_code": to_0x_hex_str(user_operation.init_code), + "call_data": to_0x_hex_str(user_operation.call_data), "call_gas_limit": user_operation.call_gas_limit, "verification_gas_limit": user_operation.verification_gas_limit, "pre_verification_gas": user_operation.pre_verification_gas, @@ -341,7 +338,7 @@ def test_safe_operation_create_view( { "non_field_errors": [ ErrorDetail( - string=f"Signer={account.address} is not an owner. Current owners=[]. Safe-operation-hash={safe_operation_hash.hex()}", + string=f"Signer={account.address} is not an owner. Current owners=[]. Safe-operation-hash={to_0x_hex_str(safe_operation_hash)}", code="invalid", ) ] @@ -447,10 +444,10 @@ def test_safe_operation_create_view( # Receipt will only be created when Operation is indexed self.assertEqual(models.UserOperationReceipt.objects.count(), 0) self.assertEqual( - models.UserOperation.objects.get().hash, user_operation_hash.hex() + models.UserOperation.objects.get().hash, to_0x_hex_str(user_operation_hash) ) self.assertEqual( - models.SafeOperation.objects.get().hash, safe_operation_hash.hex() + models.SafeOperation.objects.get().hash, to_0x_hex_str(safe_operation_hash) ) # Try to create the same transaction @@ -465,7 +462,7 @@ def test_safe_operation_create_view( { "non_field_errors": [ ErrorDetail( - string=f"SafeOperation with hash={safe_operation_hash.hex()} already exists", + string=f"SafeOperation with hash={to_0x_hex_str(safe_operation_hash)} already exists", code="invalid", ) ] @@ -519,7 +516,7 @@ def test_safe_operation_valid_until_create_view( user_operation_hash = safe_4337_user_operation_hash_mock user_operation = UserOperationClass.from_bundler_response( - user_operation_hash.hex(), user_operation_mock["result"] + to_0x_hex_str(user_operation_hash), user_operation_mock["result"] ) safe_operation = SafeOperationClass.from_user_operation(user_operation) @@ -532,11 +529,13 @@ def test_safe_operation_valid_until_create_view( ), ) - signature = account.signHash(safe_operation_hash)["signature"].hex() + signature = to_0x_hex_str( + account.unsafe_sign_hash(safe_operation_hash)["signature"] + ) data = { "nonce": safe_operation.nonce, - "init_code": user_operation.init_code.hex(), - "call_data": user_operation.call_data.hex(), + "init_code": to_0x_hex_str(user_operation.init_code), + "call_data": to_0x_hex_str(user_operation.call_data), "call_gas_limit": user_operation.call_gas_limit, "verification_gas_limit": user_operation.verification_gas_limit, "pre_verification_gas": user_operation.pre_verification_gas, @@ -585,7 +584,9 @@ def test_safe_operation_valid_until_create_view( safe_operation_hash = new_safe_operation.get_safe_operation_hash( safe_4337_chain_id_mock, safe_4337_module_address_mock ) - data["signature"] = account.signHash(safe_operation_hash)["signature"].hex() + data["signature"] = to_0x_hex_str( + account.unsafe_sign_hash(safe_operation_hash)["signature"] + ) response = self.client.post( reverse("v1:account_abstraction:safe-operations", args=(safe_address,)), format="json", @@ -620,7 +621,7 @@ def test_safe_operation_paymaster_and_data_create_view( paymaster_and_data = HexBytes(paymaster_address) user_operation = dataclasses.replace( UserOperationClass.from_bundler_response( - user_operation_hash.hex(), user_operation_mock["result"] + user_operation_hash, user_operation_mock["result"] ), paymaster_and_data=paymaster_and_data, ) @@ -630,11 +631,13 @@ def test_safe_operation_paymaster_and_data_create_view( safe_4337_chain_id_mock, safe_4337_module_address_mock ) - signature = account.signHash(safe_operation_hash)["signature"].hex() + signature = to_0x_hex_str( + account.unsafe_sign_hash(safe_operation_hash)["signature"] + ) data = { "nonce": safe_operation.nonce, - "init_code": user_operation.init_code.hex(), - "call_data": user_operation.call_data.hex(), + "init_code": to_0x_hex_str(user_operation.init_code), + "call_data": to_0x_hex_str(user_operation.call_data), "call_gas_limit": user_operation.call_gas_limit, "verification_gas_limit": user_operation.verification_gas_limit, "pre_verification_gas": user_operation.pre_verification_gas, @@ -675,7 +678,7 @@ def test_safe_operation_paymaster_and_data_create_view( ) # Set valid paymaster_and_data - data["paymaster_and_data"] = paymaster_and_data.hex() + data["paymaster_and_data"] = to_0x_hex_str(paymaster_and_data) response = self.client.post( reverse("v1:account_abstraction:safe-operations", args=(safe_address,)), format="json", @@ -720,7 +723,7 @@ def test_safe_operation_confirmations_get_view(self): response = self.client.get( reverse( endpoint, - args=(random_hash.hex(),), + args=(to_0x_hex_str(random_hash),), ) ) expected_empty = {"count": 0, "next": None, "previous": None, "results": []} @@ -768,7 +771,7 @@ def test_safe_operation_confirmations_get_view(self): "created": datetime_to_str(safe_operation_confirmation.created), "modified": datetime_to_str(safe_operation_confirmation.modified), "owner": safe_operation_confirmation.owner, - "signature": safe_operation_confirmation.signature.hex(), + "signature": to_0x_hex_str(safe_operation_confirmation.signature), "signature_type": SafeSignatureType( safe_operation_confirmation.signature_type ).name, @@ -788,11 +791,15 @@ def test_safe_operation_confirmations_post_view(self, get_owners_mock: MagicMock owner_2 = Account.create() get_owners_mock.return_value = [owner_1.address, owner_2.address] - data = {"signature": owner_1.signHash(random_hash)["signature"].hex()} + data = { + "signature": to_0x_hex_str( + owner_1.unsafe_sign_hash(random_hash)["signature"] + ) + } response = self.client.post( reverse( endpoint, - args=(random_hash.hex(),), + args=(to_0x_hex_str(random_hash),), ), format="json", data=data, @@ -803,7 +810,7 @@ def test_safe_operation_confirmations_post_view(self, get_owners_mock: MagicMock { "non_field_errors": [ ErrorDetail( - string=f"SafeOperation with hash={random_hash.hex()} does not exist", + string=f"SafeOperation with hash={to_0x_hex_str(random_hash)} does not exist", code="invalid", ) ] @@ -815,7 +822,11 @@ def test_safe_operation_confirmations_post_view(self, get_owners_mock: MagicMock # Check no confirmation exists self.assertEqual(models.SafeOperationConfirmation.objects.all().count(), 0) # Add confirmation for owner_1 - data = {"signature": owner_1.signHash(safe_operation.hash)["signature"].hex()} + data = { + "signature": to_0x_hex_str( + owner_1.unsafe_sign_hash(safe_operation.hash)["signature"] + ) + } response = self.client.post( reverse( endpoint, @@ -832,7 +843,11 @@ def test_safe_operation_confirmations_post_view(self, get_owners_mock: MagicMock self.assertEqual(safe_operation_confirmation_1.safe_operation, safe_operation) # Add confirmation for owner_2 - data = {"signature": owner_2.signHash(safe_operation.hash)["signature"].hex()} + data = { + "signature": to_0x_hex_str( + owner_2.unsafe_sign_hash(safe_operation.hash)["signature"] + ) + } response = self.client.post( reverse( endpoint, @@ -851,7 +866,9 @@ def test_safe_operation_confirmations_post_view(self, get_owners_mock: MagicMock # Try to add confirmation for random owner random_owner = Account.create() data = { - "signature": random_owner.signHash(safe_operation.hash)["signature"].hex() + "signature": to_0x_hex_str( + random_owner.unsafe_sign_hash(safe_operation.hash)["signature"] + ) } response = self.client.post( reverse( @@ -930,8 +947,9 @@ def test_user_operation_view(self): "validUntil": datetime_to_str(safe_operation.valid_until), "moduleAddress": safe_operation.module_address, "confirmations": [], - "preparedSignature": "0x" - + safe_operation.build_signature_prefix().hex(), + "preparedSignature": to_0x_hex_str( + safe_operation.build_signature_prefix() + ), }, } self.assertDictEqual( @@ -990,8 +1008,9 @@ def test_user_operations_view(self): "validUntil": datetime_to_str(safe_operation.valid_until), "moduleAddress": safe_operation.module_address, "confirmations": [], - "preparedSignature": "0x" - + safe_operation.build_signature_prefix().hex(), + "preparedSignature": to_0x_hex_str( + safe_operation.build_signature_prefix() + ), }, } self.assertDictEqual( diff --git a/safe_transaction_service/contracts/tests/test_tx_decoder.py b/safe_transaction_service/contracts/tests/test_tx_decoder.py index 14b2e6c13..e5eda2eeb 100644 --- a/safe_transaction_service/contracts/tests/test_tx_decoder.py +++ b/safe_transaction_service/contracts/tests/test_tx_decoder.py @@ -5,6 +5,7 @@ from hexbytes import HexBytes from safe_eth.eth.constants import NULL_ADDRESS from safe_eth.safe.multi_send import MultiSendOperation +from safe_eth.util.util import to_0x_hex_str from web3 import Web3 from safe_transaction_service.contracts.tests.factories import ( @@ -186,7 +187,7 @@ def test_decode_multisend(self): "operation": operation, "to": safe_contract_address, "value": value, - "data": change_master_copy_data.hex(), + "data": to_0x_hex_str(change_master_copy_data), "data_decoded": { "method": "changeMasterCopy", "parameters": [ @@ -202,7 +203,7 @@ def test_decode_multisend(self): "operation": operation, "to": safe_contract_address, "value": value, - "data": change_fallback_manager_data.hex(), + "data": to_0x_hex_str(change_fallback_manager_data), "data_decoded": { "method": "setFallbackHandler", "parameters": [ @@ -231,7 +232,7 @@ def test_decode_multisend(self): "operation": operation, "to": safe_contract_address, "value": value, - "data": change_master_copy_data.hex(), + "data": to_0x_hex_str(change_master_copy_data), "data_decoded": { "method": "changeMasterCopy", "parameters": [ @@ -247,7 +248,7 @@ def test_decode_multisend(self): "operation": operation, "to": safe_contract_address, "value": value, - "data": change_fallback_manager_data.hex(), + "data": to_0x_hex_str(change_fallback_manager_data), "data_decoded": { "method": "setFallbackHandler", "parameters": [ diff --git a/safe_transaction_service/contracts/tx_decoder.py b/safe_transaction_service/contracts/tx_decoder.py index eb2250118..105e2331f 100644 --- a/safe_transaction_service/contracts/tx_decoder.py +++ b/safe_transaction_service/contracts/tx_decoder.py @@ -21,7 +21,7 @@ from cachetools import TTLCache, cachedmethod from eth_abi import decode as decode_abi from eth_abi.exceptions import DecodingError -from eth_typing import ChecksumAddress, HexStr +from eth_typing import ABIFunction, ChecksumAddress, HexStr from eth_utils import function_abi_to_4byte_selector from hexbytes import HexBytes from safe_eth.eth.contracts import ( @@ -38,11 +38,11 @@ get_uniswap_exchange_contract, ) from safe_eth.safe.multi_send import MultiSend +from safe_eth.util.util import to_0x_hex_str from web3 import Web3 from web3._utils.abi import get_abi_input_names, get_abi_input_types, map_abi_data from web3._utils.normalizers import BASE_RETURN_NORMALIZERS from web3.contract import Contract -from web3.types import ABIFunction from safe_transaction_service.contracts.models import ContractAbi from safe_transaction_service.utils.utils import running_on_gevent @@ -212,7 +212,10 @@ def _decode_data( params = data[4:] fn_abi = self.get_abi_function(data, address) if not fn_abi: - raise CannotDecode(data.hex()) + # Check if the contract has a fallback call and return a minimal ABIFunction for fallback call + if address and self.has_contract_fallback_function(address): + return "fallback", [] + raise CannotDecode(to_0x_hex_str(data)) try: names = get_abi_input_names(fn_abi) types = get_abi_input_types(fn_abi) @@ -220,7 +223,7 @@ def _decode_data( normalized = map_abi_data(BASE_RETURN_NORMALIZERS, types, decoded) values = map(self._parse_decoded_arguments, normalized) except (ValueError, DecodingError) as exc: - logger.warning("Cannot decode %s", data.hex()) + logger.warning("Cannot decode %s", to_0x_hex_str(data)) raise UnexpectedProblemDecoding(data) from exc return fn_abi["name"], list(zip(names, types, values)) @@ -263,7 +266,7 @@ def _parse_decoded_arguments(self, value_decoded: Any) -> Any: :return: Dict[str, Any] """ if isinstance(value_decoded, bytes): - value_decoded = HexBytes(value_decoded).hex() + value_decoded = to_0x_hex_str(HexBytes(value_decoded)) return value_decoded def add_abi(self, abi: ABIFunction) -> bool: @@ -397,7 +400,9 @@ def decode_multisend_data(self, data: Union[bytes, str]) -> List[MultisendDecode "operation": multisend_tx.operation.value, "to": multisend_tx.to, "value": str(multisend_tx.value), - "data": multisend_tx.data.hex() if multisend_tx.data else None, + "data": ( + to_0x_hex_str(multisend_tx.data) if multisend_tx.data else None + ), "data_decoded": self.get_data_decoded( multisend_tx.data, address=multisend_tx.to ), @@ -407,7 +412,7 @@ def decode_multisend_data(self, data: Union[bytes, str]) -> List[MultisendDecode except ValueError: logger.warning( "Problem decoding multisend transaction with data=%s", - HexBytes(data).hex(), + to_0x_hex_str(HexBytes(data)), exc_info=True, ) @@ -569,23 +574,19 @@ def get_contract_abi(self, address: ChecksumAddress) -> Optional[List[ABIFunctio .first() ) - def get_contract_fallback_function( - self, address: ChecksumAddress - ) -> Optional[ABIFunction]: + def has_contract_fallback_function(self, address: ChecksumAddress) -> bool: """ :param address: Contract address :return: Fallback ABIFunction if found, `None` otherwise. """ abi = self.get_contract_abi(address) - if abi: - return next( - ( - dict(fn_abi, name="fallback") - for fn_abi in abi - if fn_abi.get("type") == "fallback" - ), - None, - ) + if not abi: + return False + return bool( + dict(fn_abi, name="fallback") + for fn_abi in abi + if fn_abi.get("type") == "fallback" + ) @cachedmethod( cache=operator.attrgetter( @@ -627,9 +628,6 @@ def get_abi_function( # Otherwise we fall back to the general abi that matches the selector return contract_selectors_with_abis[selector] return self.fn_selectors_with_abis[selector] - # Check if the contract has a fallback call and return a minimal ABIFunction for fallback call - elif address: - return self.get_contract_fallback_function(address) def get_supported_abis(self) -> Iterable[Type[Contract]]: supported_abis = super().get_supported_abis() diff --git a/safe_transaction_service/history/admin.py b/safe_transaction_service/history/admin.py index 40aa2054f..0bbdd6ff2 100644 --- a/safe_transaction_service/history/admin.py +++ b/safe_transaction_service/history/admin.py @@ -12,6 +12,7 @@ from safe_eth.eth import get_auto_ethereum_client from safe_eth.eth.django.admin import AdvancedAdminSearchMixin from safe_eth.safe import SafeTx +from safe_eth.util.util import to_0x_hex_str from .models import ( Chain, @@ -444,7 +445,7 @@ class ModuleTransactionAdmin(AdvancedAdminSearchMixin, admin.ModelAdmin): search_fields = ["==safe", "==module", "==to"] def data_hex(self, o: ModuleTransaction): - return HexBytes(o.data).hex() if o.data else None + return to_0x_hex_str(HexBytes(o.data)) if o.data else None def tx_hash(self, o: ModuleTransaction): return o.internal_tx.ethereum_tx_id diff --git a/safe_transaction_service/history/indexers/element_already_processed_checker.py b/safe_transaction_service/history/indexers/element_already_processed_checker.py index 590677444..84f17c2f5 100644 --- a/safe_transaction_service/history/indexers/element_already_processed_checker.py +++ b/safe_transaction_service/history/indexers/element_already_processed_checker.py @@ -2,6 +2,7 @@ from typing import Optional from hexbytes import HexBytes +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.utils.utils import FixedSizeDict @@ -53,16 +54,16 @@ def mark_as_processed( if tx_id in self._processed_element_cache: logger.debug( "Element with tx-hash=%s on block=%s with index=%d was already processed", - tx_hash.hex(), - block_hash.hex(), + to_0x_hex_str(tx_hash), + to_0x_hex_str(block_hash), index, ) return False else: logger.debug( "Marking element with tx-hash=%s on block=%s with index=%d as processed", - tx_hash.hex(), - block_hash.hex(), + to_0x_hex_str(tx_hash), + to_0x_hex_str(block_hash), index, ) self._processed_element_cache[tx_id] = None diff --git a/safe_transaction_service/history/indexers/events_indexer.py b/safe_transaction_service/history/indexers/events_indexer.py index 6f9701f9f..43cbd7193 100644 --- a/safe_transaction_service/history/indexers/events_indexer.py +++ b/safe_transaction_service/history/indexers/events_indexer.py @@ -11,6 +11,7 @@ from eth_utils import event_abi_to_log_topic from gevent import pool from hexbytes import HexBytes +from safe_eth.util.util import to_0x_hex_str from web3.contract.contract import ContractEvent from web3.exceptions import LogTopicError from web3.types import EventData, FilterParams, LogReceipt @@ -75,7 +76,7 @@ def events_to_listen(self) -> Dict[HexStr, List[ContractEvent]]: """ events_to_listen = {} for event in self.contract_events: - key = HexStr(HexBytes(event_abi_to_log_topic(event.abi)).hex()) + key = to_0x_hex_str(HexBytes(event_abi_to_log_topic(event.abi))) events_to_listen.setdefault(key, []).append(event) return events_to_listen @@ -221,7 +222,7 @@ def decode_element(self, log_receipt: LogReceipt) -> Optional[EventData]: or `None` if decoding was not possible """ for event_to_listen in self.events_to_listen[ - HexStr(log_receipt["topics"][0].hex()) + to_0x_hex_str(log_receipt["topics"][0]) ]: # Try to decode using all the existing ABIs # One topic can have multiple matching ABIs due to `indexed` elements changing how to decode it diff --git a/safe_transaction_service/history/indexers/internal_tx_indexer.py b/safe_transaction_service/history/indexers/internal_tx_indexer.py index 6e66cef9f..26653092d 100644 --- a/safe_transaction_service/history/indexers/internal_tx_indexer.py +++ b/safe_transaction_service/history/indexers/internal_tx_indexer.py @@ -8,6 +8,7 @@ from eth_typing import ChecksumAddress, HexStr from hexbytes import HexBytes from safe_eth.eth import EthereumClient +from safe_eth.util.util import to_0x_hex_str from web3.types import BlockTrace, FilterTrace from safe_transaction_service.contracts.tx_decoder import ( @@ -251,9 +252,11 @@ def _get_internal_txs_to_decode( processed=False, ) except CannotDecode as exc: - logger.debug("Cannot decode %s: %s", data.hex(), exc) + logger.debug("Cannot decode %s: %s", to_0x_hex_str(data), exc) except UnexpectedProblemDecoding as exc: - logger.warning("Unexpected problem decoding %s: %s", data.hex(), exc) + logger.warning( + "Unexpected problem decoding %s: %s", to_0x_hex_str(data), exc + ) def trace_transactions( self, tx_hashes: Sequence[HexStr], batch_size: int diff --git a/safe_transaction_service/history/indexers/proxy_factory_indexer.py b/safe_transaction_service/history/indexers/proxy_factory_indexer.py index 53adb4478..46c7d8894 100644 --- a/safe_transaction_service/history/indexers/proxy_factory_indexer.py +++ b/safe_transaction_service/history/indexers/proxy_factory_indexer.py @@ -9,6 +9,7 @@ get_proxy_factory_V1_3_0_contract, get_proxy_factory_V1_4_1_contract, ) +from safe_eth.util.util import to_0x_hex_str from web3.contract.contract import ContractEvent from web3.types import EventData, LogReceipt @@ -72,7 +73,7 @@ def _process_decoded_element( contract_address = decoded_element["args"]["proxy"] if contract_address != NULL_ADDRESS: if (block_number := decoded_element["blockNumber"]) == 0: - transaction_hash = decoded_element["transactionHash"].hex() + transaction_hash = to_0x_hex_str(decoded_element["transactionHash"]) log_msg = ( f"Events are reporting blockNumber=0 for tx-hash={transaction_hash}" ) diff --git a/safe_transaction_service/history/indexers/safe_events_indexer.py b/safe_transaction_service/history/indexers/safe_events_indexer.py index 15c3df87e..093410d45 100644 --- a/safe_transaction_service/history/indexers/safe_events_indexer.py +++ b/safe_transaction_service/history/indexers/safe_events_indexer.py @@ -17,6 +17,7 @@ get_safe_V1_3_0_contract, get_safe_V1_4_1_contract, ) +from safe_eth.util.util import to_0x_hex_str from web3.contract.contract import ContractEvent from web3.types import EventData @@ -345,7 +346,7 @@ def _process_decoded_element( trace_address = str(log_index) args = dict(decoded_element["args"]) ethereum_tx_hash = HexBytes(decoded_element["transactionHash"]) - ethereum_tx_hash_hex = ethereum_tx_hash.hex() + ethereum_tx_hash_hex = to_0x_hex_str(ethereum_tx_hash) ethereum_block_timestamp = EthereumBlock.objects.get_timestamp_by_hash( decoded_element["blockHash"] ) @@ -377,8 +378,8 @@ def _process_decoded_element( elif event_name == "SafeMultiSigTransaction": internal_tx_decoded.function_name = "execTransaction" data = HexBytes(args["data"]) - args["data"] = data.hex() - args["signatures"] = HexBytes(args["signatures"]).hex() + args["data"] = to_0x_hex_str(data) + args["signatures"] = to_0x_hex_str(HexBytes(args["signatures"])) additional_info = HexBytes( internal_tx_decoded.arguments.pop("additionalInfo") ) @@ -393,7 +394,7 @@ def _process_decoded_element( safe_address, event_name, ethereum_tx_hash_hex, - additional_info.hex(), + to_0x_hex_str(additional_info), ) if args["value"] and not data: # Simulate ether transfer child_internal_tx = self._get_internal_tx_from_decoded_event( @@ -405,10 +406,10 @@ def _process_decoded_element( elif event_name == "SafeModuleTransaction": internal_tx_decoded.function_name = "execTransactionFromModule" - args["data"] = HexBytes(args["data"]).hex() + args["data"] = to_0x_hex_str(HexBytes(args["data"])) elif event_name == "ApproveHash": internal_tx_decoded.function_name = "approveHash" - args["hashToApprove"] = args.pop("approvedHash").hex() + args["hashToApprove"] = to_0x_hex_str(args.pop("approvedHash")) elif event_name == "EnabledModule": internal_tx_decoded.function_name = "enableModule" elif event_name == "DisabledModule": @@ -464,7 +465,7 @@ def _process_decoded_element( "Ignoring already processed event %s for Safe %s on tx-hash=%s: %s", event_name, safe_address, - decoded_element["transactionHash"].hex(), + to_0x_hex_str(decoded_element["transactionHash"]), exc, ) return None @@ -624,7 +625,7 @@ def _process_safe_creation_events( except IntegrityError: logger.info( "Ignoring already processed InternalTx with tx-hash=%s and trace-address=%s", - internal_decoded_tx.internal_tx.ethereum_tx_id.hex(), + to_0x_hex_str(internal_decoded_tx.internal_tx.ethereum_tx_id), internal_decoded_tx.internal_tx.trace_address, ) pass @@ -637,7 +638,7 @@ def _process_safe_creation_events( except IntegrityError: logger.info( "Ignoring already processed InternalTx with tx-hash=%s and trace-address=%s", - internal_tx.ethereum_tx_id.hex(), + to_0x_hex_str(internal_tx.ethereum_tx_id), internal_tx.trace_address, ) pass diff --git a/safe_transaction_service/history/indexers/tx_processor.py b/safe_transaction_service/history/indexers/tx_processor.py index 4fac1305e..7e2136623 100644 --- a/safe_transaction_service/history/indexers/tx_processor.py +++ b/safe_transaction_service/history/indexers/tx_processor.py @@ -21,7 +21,9 @@ ) from safe_eth.safe import SafeTx from safe_eth.safe.safe_signature import SafeSignature, SafeSignatureApprovedHash +from safe_eth.util.util import to_0x_hex_str from web3 import Web3 +from web3.exceptions import Web3RPCError from safe_transaction_service.account_abstraction.services import ( AaProcessorService, @@ -420,7 +422,7 @@ def __process_decoded_transaction( logger.debug( "[%s] Start processing InternalTxDecoded in tx-hash=%s", contract_address, - HexBytes(internal_tx_decoded.internal_tx.ethereum_tx_id).hex(), + to_0x_hex_str(HexBytes(internal_tx_decoded.internal_tx.ethereum_tx_id)), ) if internal_tx.gas_used < 1000: @@ -562,17 +564,21 @@ def __process_decoded_transaction( # Regular Safe indexed using tracing # Someone calls Module -> Module calls Safe Proxy -> Safe Proxy delegate calls Master Copy # The trace that is being processed is the last one, so indexer needs to get the previous trace - previous_trace = ( - self.ethereum_tracing_client.tracing.get_previous_trace( - internal_tx.ethereum_tx_id, - internal_tx.trace_address_as_list, - skip_delegate_calls=True, + try: + previous_trace = ( + self.ethereum_tracing_client.tracing.get_previous_trace( + internal_tx.ethereum_tx_id, + internal_tx.trace_address_as_list, + skip_delegate_calls=True, + ) ) - ) + except Web3RPCError: + previous_trace = None + if not previous_trace: message = ( f"[{contract_address}] Cannot find previous trace for " - f"tx-hash={HexBytes(internal_tx.ethereum_tx_id).hex()} " + f"tx-hash={to_0x_hex_str(HexBytes(internal_tx.ethereum_tx_id))} " f"and trace-address={internal_tx.trace_address}" ) logger.warning(message) @@ -632,7 +638,7 @@ def __process_decoded_transaction( ) if not previous_trace: message = ( - f"[{contract_address}] Cannot find previous trace for tx-hash={HexBytes(internal_tx.ethereum_tx_id).hex()} and " + f"[{contract_address}] Cannot find previous trace for tx-hash={to_0x_hex_str(HexBytes(internal_tx.ethereum_tx_id))} and " f"trace-address={internal_tx.trace_address}" ) logger.warning(message) diff --git a/safe_transaction_service/history/models.py b/safe_transaction_service/history/models.py index bd60c7f85..4d9f9a282 100644 --- a/safe_transaction_service/history/models.py +++ b/safe_transaction_service/history/models.py @@ -55,6 +55,7 @@ from safe_eth.safe import SafeOperationEnum from safe_eth.safe.safe import SafeInfo from safe_eth.safe.safe_signature import SafeSignature, SafeSignatureType +from safe_eth.util.util import to_0x_hex_str from web3.types import EventData from safe_transaction_service.account_abstraction.constants import ( @@ -250,8 +251,8 @@ def create_from_block( timestamp=datetime.datetime.fromtimestamp( block["timestamp"], datetime.timezone.utc ), - block_hash=block["hash"].hex(), - parent_hash=block["parentHash"].hex(), + block_hash=to_0x_hex_str(block["hash"]), + parent_hash=to_0x_hex_str(block["parentHash"]), confirmed=confirmed, ) except IntegrityError: @@ -264,7 +265,7 @@ def create_from_block( db_block.confirmed = False # Will be taken care of by the reorg task db_block.save(update_fields=["confirmed"]) raise IntegrityError( - f"Error inserting block with hash={block['hash'].hex()}, " + f"Error inserting block with hash={to_0x_hex_str(block['hash'])}, " f"there is a block with the same number={block['number']} inserted. " f"Marking block as not confirmed" ) @@ -275,7 +276,8 @@ def get_timestamp_by_hash(self, block_hash: HexBytes) -> datetime.datetime: return self.values("timestamp").get(block_hash=block_hash)["timestamp"] except self.model.DoesNotExist: logger.error( - "Block with hash=%s does not exist on database", block_hash.hex() + "Block with hash=%s does not exist on database", + to_0x_hex_str(block_hash), ) raise @@ -361,7 +363,7 @@ def create_from_tx_dict( return super().create( block=ethereum_block, - tx_hash=HexBytes(tx["hash"]).hex(), + tx_hash=to_0x_hex_str(HexBytes(tx["hash"])), gas_used=tx_receipt and tx_receipt["gasUsed"], _from=tx["from"], gas=tx["gas"], @@ -382,7 +384,7 @@ def account_abstraction_txs(self) -> RawQuerySet: """ :return: Transactions containing ERC4337 `UserOperation` event """ - query = '{"topics": ["' + USER_OPERATION_EVENT_TOPIC.hex() + '"]}' + query = '{"topics": ["' + to_0x_hex_str(USER_OPERATION_EVENT_TOPIC) + '"]}' return self.raw( f"SELECT * FROM history_ethereumtx WHERE '{query}'::jsonb <@ ANY (logs)" @@ -568,7 +570,7 @@ def _prepare_parameters_from_decoded_event(event_data: EventData) -> Dict[str, A expected_topic = HexBytes(ERC20_721_TRANSFER_TOPIC) if topic != expected_topic: raise ValueError( - f"Not supported EventData, topic {topic.hex()} does not match expected {expected_topic.hex()}" + f"Not supported EventData, topic {to_0x_hex_str(topic)} does not match expected {to_0x_hex_str(expected_topic)}" ) try: @@ -1059,11 +1061,11 @@ class Meta: def __str__(self): if self.to: return "Internal tx hash={} from={} to={}".format( - HexBytes(self.ethereum_tx_id).hex(), self._from, self.to + to_0x_hex_str(HexBytes(self.ethereum_tx_id)), self._from, self.to ) else: return "Internal tx hash={} from={}".format( - HexBytes(self.ethereum_tx_id).hex(), self._from + to_0x_hex_str(HexBytes(self.ethereum_tx_id)), self._from ) @property @@ -1603,7 +1605,7 @@ def __str__(self): if self.value: return f"{self.safe} - {self.to} - {self.value}" else: - return f"{self.safe} - {self.to} - 0x{bytes(self.data).hex()[:6]}" + return f"{self.safe} - {self.to} - {to_0x_hex_str(bytes(self.data))[:6]}" @property def unique_id(self): diff --git a/safe_transaction_service/history/serializers.py b/safe_transaction_service/history/serializers.py index c992bf0dd..1289f7c17 100644 --- a/safe_transaction_service/history/serializers.py +++ b/safe_transaction_service/history/serializers.py @@ -24,6 +24,7 @@ from safe_eth.safe import Safe from safe_eth.safe.safe_signature import EthereumBytes, SafeSignature, SafeSignatureType from safe_eth.safe.serializers import SafeMultisigTxSerializer +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.account_abstraction import serializers as aa_serializers from safe_transaction_service.contracts.tx_decoder import ( @@ -125,7 +126,7 @@ def validate_signature(self, signature: bytes): ) if not safe_signature.is_valid(ethereum_client, safe_address): raise ValidationError( - f"Signature={safe_signature.signature.hex()} for owner={owner} is not valid" + f"Signature={to_0x_hex_str(safe_signature.signature)} for owner={owner} is not valid" ) if owner in signature_owners: raise ValidationError(f"Signature for owner={owner} is duplicated") @@ -203,8 +204,8 @@ def validate(self, attrs): # Check safe tx hash matches if safe_tx_hash != attrs["contract_transaction_hash"]: raise ValidationError( - f"Contract-transaction-hash={safe_tx_hash.hex()} " - f'does not match provided contract-tx-hash={attrs["contract_transaction_hash"].hex()}' + f"Contract-transaction-hash={to_0x_hex_str(safe_tx_hash)} " + f'does not match provided contract-tx-hash={to_0x_hex_str(attrs["contract_transaction_hash"])}' ) # Check there's not duplicated tx with same `nonce` or same `safeTxHash` for the same Safe. @@ -214,9 +215,9 @@ def validate(self, attrs): ).executed() if multisig_transactions: for multisig_transaction in multisig_transactions: - if multisig_transaction.safe_tx_hash == safe_tx_hash.hex(): + if multisig_transaction.safe_tx_hash == to_0x_hex_str(safe_tx_hash): raise ValidationError( - f"Tx with safe-tx-hash={safe_tx_hash.hex()} " + f"Tx with safe-tx-hash={to_0x_hex_str(safe_tx_hash)} " f"for safe={safe_address} was already executed in " f"tx-hash={multisig_transaction.ethereum_tx_id}" ) @@ -252,7 +253,7 @@ def validate(self, attrs): owner = safe_signature.owner if not safe_signature.is_valid(ethereum_client, safe_address): raise ValidationError( - f"Signature={safe_signature.signature.hex()} for owner={owner} is not valid" + f"Signature={to_0x_hex_str(safe_signature.signature)} for owner={owner} is not valid" ) if owner in delegates and len(parsed_signatures) > 1: diff --git a/safe_transaction_service/history/services/index_service.py b/safe_transaction_service/history/services/index_service.py index 718911359..d420040e5 100644 --- a/safe_transaction_service/history/services/index_service.py +++ b/safe_transaction_service/history/services/index_service.py @@ -8,6 +8,7 @@ from eth_typing import ChecksumAddress from hexbytes import HexBytes from safe_eth.eth import EthereumClient, get_auto_ethereum_client +from safe_eth.util.util import to_0x_hex_str from ..models import EthereumBlock, EthereumTx from ..models import IndexingStatus as IndexingStatusDb @@ -252,7 +253,7 @@ def txs_create_or_update_from_tx_hashes( logger.debug("Don't retrieve existing txs on DB. Find them first") # Search first in database ethereum_txs_dict = OrderedDict.fromkeys( - [HexBytes(tx_hash).hex() for tx_hash in tx_hashes] + [to_0x_hex_str(HexBytes(tx_hash)) for tx_hash in tx_hashes] ) db_ethereum_txs = EthereumTx.objects.filter(tx_hash__in=tx_hashes).exclude( block=None @@ -283,13 +284,13 @@ def txs_create_or_update_from_tx_hashes( ) # Retry fetching if failed if not tx_receipt: raise TransactionNotFoundException( - f"Cannot find tx-receipt with tx-hash={HexBytes(tx_hash).hex()}" + f"Cannot find tx-receipt with tx-hash={to_0x_hex_str(HexBytes(tx_hash))}" ) if tx_receipt.get("blockHash") is None: raise TransactionWithoutBlockException( f"Cannot find blockHash for tx-receipt with " - f"tx-hash={HexBytes(tx_hash).hex()}" + f"tx-hash={to_0x_hex_str(HexBytes(tx_hash))}" ) tx_receipts.append(tx_receipt) @@ -305,16 +306,16 @@ def txs_create_or_update_from_tx_hashes( ) # Retry fetching if failed if not tx: raise TransactionNotFoundException( - f"Cannot find tx with tx-hash={HexBytes(tx_hash).hex()}" + f"Cannot find tx with tx-hash={to_0x_hex_str(HexBytes(tx_hash))}" ) if tx.get("blockHash") is None: raise TransactionWithoutBlockException( f"Cannot find blockHash for tx with " - f"tx-hash={HexBytes(tx_hash).hex()}" + f"tx-hash={to_0x_hex_str(HexBytes(tx_hash))}" ) - block_hashes.add(tx["blockHash"].hex()) + block_hashes.add(to_0x_hex_str(tx["blockHash"])) txs.append(tx) logger.debug("Got txs from RPC. Getting %d blocks", len(block_hashes)) @@ -328,7 +329,7 @@ def txs_create_or_update_from_tx_hashes( raise BlockNotFoundException( f"Block with hash={block_hash} was not found" ) - assert block_hash == block["hash"].hex() + assert block_hash == to_0x_hex_str(block["hash"]) block_dict[block["hash"]] = block logger.debug( @@ -352,7 +353,9 @@ def txs_create_or_update_from_tx_hashes( ethereum_tx = EthereumTx.objects.create_from_tx_dict( tx, tx_receipt=tx_receipt, ethereum_block=ethereum_block ) - ethereum_txs_dict[HexBytes(ethereum_tx.tx_hash).hex()] = ethereum_tx + ethereum_txs_dict[to_0x_hex_str(HexBytes(ethereum_tx.tx_hash))] = ( + ethereum_tx + ) except IntegrityError: # Tx exists ethereum_tx = EthereumTx.objects.get(tx_hash=tx["hash"]) # For txs stored before being mined @@ -422,7 +425,7 @@ def fix_out_of_order( """ timestamp = internal_tx.timestamp - tx_hash_hex = HexBytes(internal_tx.ethereum_tx_id).hex() + tx_hash_hex = to_0x_hex_str(HexBytes(internal_tx.ethereum_tx_id)) logger.info( "[%s] Fixing out of order from tx %s with timestamp %s", address, diff --git a/safe_transaction_service/history/services/notification_service.py b/safe_transaction_service/history/services/notification_service.py index f8174f57b..00f574f2e 100644 --- a/safe_transaction_service/history/services/notification_service.py +++ b/safe_transaction_service/history/services/notification_service.py @@ -6,6 +6,7 @@ from django.utils import timezone from hexbytes import HexBytes +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.history.models import ( ERC20Transfer, @@ -51,9 +52,9 @@ def build_event_payload( "address": instance.multisig_transaction.safe, # This could make a db call "type": TransactionServiceEventType.NEW_CONFIRMATION.name, "owner": instance.owner, - "safeTxHash": HexBytes( - instance.multisig_transaction.safe_tx_hash - ).hex(), + "safeTxHash": to_0x_hex_str( + HexBytes(instance.multisig_transaction.safe_tx_hash) + ), } ] elif sender == MultisigTransaction and deleted: @@ -61,16 +62,16 @@ def build_event_payload( { "address": instance.safe, "type": TransactionServiceEventType.DELETED_MULTISIG_TRANSACTION.name, - "safeTxHash": HexBytes(instance.safe_tx_hash).hex(), + "safeTxHash": to_0x_hex_str(HexBytes(instance.safe_tx_hash)), } ] elif sender == MultisigTransaction: payload = { "address": instance.safe, # 'type': None, It will be assigned later - "safeTxHash": HexBytes(instance.safe_tx_hash).hex(), + "safeTxHash": to_0x_hex_str(HexBytes(instance.safe_tx_hash)), "to": instance.to, - "data": HexBytes(instance.data).hex() if instance.data else None, + "data": to_0x_hex_str(HexBytes(instance.data)) if instance.data else None, } if instance.executed: payload["type"] = ( @@ -79,7 +80,7 @@ def build_event_payload( payload["failed"] = json.dumps( instance.failed ) # Firebase only accepts strings - payload["txHash"] = HexBytes(instance.ethereum_tx_id).hex() + payload["txHash"] = to_0x_hex_str(HexBytes(instance.ethereum_tx_id)) else: payload["type"] = ( TransactionServiceEventType.PENDING_MULTISIG_TRANSACTION.name @@ -89,7 +90,7 @@ def build_event_payload( incoming_payload = { "address": instance.to, "type": TransactionServiceEventType.INCOMING_ETHER.name, - "txHash": HexBytes(instance.ethereum_tx_id).hex(), + "txHash": to_0x_hex_str(HexBytes(instance.ethereum_tx_id)), "value": str(instance.value), } outgoing_payload = dict(incoming_payload) @@ -102,7 +103,7 @@ def build_event_payload( "address": instance.to, "type": TransactionServiceEventType.INCOMING_TOKEN.name, "tokenAddress": instance.address, - "txHash": HexBytes(instance.ethereum_tx_id).hex(), + "txHash": to_0x_hex_str(HexBytes(instance.ethereum_tx_id)), } if isinstance(instance, ERC20Transfer): incoming_payload["value"] = str(instance.value) @@ -117,7 +118,7 @@ def build_event_payload( { "address": instance.address, "type": TransactionServiceEventType.SAFE_CREATED.name, - "txHash": HexBytes(instance.ethereum_tx_id).hex(), + "txHash": to_0x_hex_str(HexBytes(instance.ethereum_tx_id)), "blockNumber": instance.created_block_number, } ] @@ -127,7 +128,7 @@ def build_event_payload( "address": instance.safe, "type": TransactionServiceEventType.MODULE_TRANSACTION.name, "module": instance.module, - "txHash": HexBytes(instance.internal_tx.ethereum_tx_id).hex(), + "txHash": to_0x_hex_str(HexBytes(instance.internal_tx.ethereum_tx_id)), } ] elif sender == SafeMessage: @@ -135,7 +136,7 @@ def build_event_payload( { "address": instance.safe, "type": TransactionServiceEventType.MESSAGE_CREATED.name, - "messageHash": HexBytes(instance.message_hash).hex(), + "messageHash": to_0x_hex_str(HexBytes(instance.message_hash)), } ] elif sender == SafeMessageConfirmation: @@ -143,7 +144,9 @@ def build_event_payload( { "address": instance.safe_message.safe, # This could make a db call "type": TransactionServiceEventType.MESSAGE_CONFIRMATION.name, - "messageHash": HexBytes(instance.safe_message.message_hash).hex(), + "messageHash": to_0x_hex_str( + HexBytes(instance.safe_message.message_hash) + ), } ] diff --git a/safe_transaction_service/history/services/reorg_service.py b/safe_transaction_service/history/services/reorg_service.py index ef6a8f669..0bd84a46a 100644 --- a/safe_transaction_service/history/services/reorg_service.py +++ b/safe_transaction_service/history/services/reorg_service.py @@ -6,6 +6,7 @@ from hexbytes import HexBytes from safe_eth.eth import EthereumClient, get_auto_ethereum_client +from safe_eth.util.util import to_0x_hex_str from ..indexers import ( Erc20EventsIndexerProvider, @@ -123,15 +124,15 @@ def check_reorgs(self) -> Optional[int]: logger.debug( "Block with number=%d and hash=%s is matching blockchain one, setting as confirmed", database_block.number, - HexBytes(blockchain_block["hash"]).hex(), + to_0x_hex_str(HexBytes(blockchain_block["hash"])), ) database_block.set_confirmed() else: logger.warning( "Block with number=%d and hash=%s is not matching blockchain hash=%s, reorg found", database_block.number, - HexBytes(database_block.block_hash).hex(), - HexBytes(blockchain_block["hash"]).hex(), + to_0x_hex_str(HexBytes(database_block.block_hash)), + to_0x_hex_str(HexBytes(blockchain_block["hash"])), ) return database_block.number diff --git a/safe_transaction_service/history/services/safe_service.py b/safe_transaction_service/history/services/safe_service.py index a467c995d..ea648ff06 100644 --- a/safe_transaction_service/history/services/safe_service.py +++ b/safe_transaction_service/history/services/safe_service.py @@ -17,6 +17,7 @@ from safe_eth.safe.multi_send import MultiSend from safe_eth.safe.safe import SafeInfo from web3 import Web3 +from web3.exceptions import Web3RPCError from safe_transaction_service.account_abstraction import models as aa_models from safe_transaction_service.utils.abis.gelato import gelato_relay_1_balance_v2_abi @@ -394,7 +395,7 @@ def _get_next_internal_tx(self, internal_tx: InternalTx) -> Optional[InternalTx] return next_traces and InternalTx.objects.build_from_trace( next_traces[0], internal_tx.ethereum_tx ) - except ValueError: + except (ValueError, Web3RPCError): return None def _get_parent_internal_tx(self, internal_tx: InternalTx) -> Optional[InternalTx]: @@ -411,5 +412,5 @@ def _get_parent_internal_tx(self, internal_tx: InternalTx) -> Optional[InternalT return previous_trace and InternalTx.objects.build_from_trace( previous_trace, internal_tx.ethereum_tx ) - except ValueError: + except (ValueError, Web3RPCError): return None diff --git a/safe_transaction_service/history/tests/factories.py b/safe_transaction_service/history/tests/factories.py index e0b179738..7cd8a291a 100644 --- a/safe_transaction_service/history/tests/factories.py +++ b/safe_transaction_service/history/tests/factories.py @@ -11,6 +11,7 @@ from safe_eth.eth.constants import NULL_ADDRESS from safe_eth.eth.utils import fast_keccak_text from safe_eth.safe.safe_signature import SafeSignatureType +from safe_eth.util.util import to_0x_hex_str from ..models import ( ERC20Transfer, @@ -53,8 +54,12 @@ class Meta: gas_limit = factory.fuzzy.FuzzyInteger(100000000, 200000000) gas_used = factory.fuzzy.FuzzyInteger(100000, 500000) timestamp = factory.LazyFunction(timezone.now) - block_hash = factory.Sequence(lambda n: fast_keccak_text(f"block-{n}").hex()) - parent_hash = factory.Sequence(lambda n: fast_keccak_text(f"block{n - 1}").hex()) + block_hash = factory.Sequence( + lambda n: to_0x_hex_str(fast_keccak_text(f"block-{n}")) + ) + parent_hash = factory.Sequence( + lambda n: to_0x_hex_str(fast_keccak_text(f"block{n - 1}")) + ) class EthereumTxFactory(DjangoModelFactory): @@ -63,7 +68,7 @@ class Meta: block = factory.SubFactory(EthereumBlockFactory) tx_hash = factory.Sequence( - lambda n: fast_keccak_text(f"ethereum_tx_hash-{n}").hex() + lambda n: to_0x_hex_str(fast_keccak_text(f"ethereum_tx_hash-{n}")) ) _from = factory.LazyFunction(lambda: Account.create().address) gas = factory.fuzzy.FuzzyInteger(1000, 5000) @@ -274,7 +279,7 @@ class Meta: model = MultisigTransaction safe_tx_hash = factory.Sequence( - lambda n: fast_keccak_text(f"multisig-tx-{n}").hex() + lambda n: to_0x_hex_str(fast_keccak_text(f"multisig-tx-{n}")) ) safe = factory.LazyFunction(lambda: Account.create().address) proposer = None @@ -313,7 +318,7 @@ class Meta: ethereum_tx = factory.SubFactory(EthereumTxFactory) multisig_transaction = factory.SubFactory(MultisigTransactionFactory) multisig_transaction_hash = factory.Sequence( - lambda n: fast_keccak_text(f"multisig-confirmation-tx-{n}").hex() + lambda n: to_0x_hex_str(fast_keccak_text(f"multisig-confirmation-tx-{n}")) ) owner = factory.LazyFunction(lambda: Account.create().address) signature = None diff --git a/safe_transaction_service/history/tests/test_internal_tx_indexer.py b/safe_transaction_service/history/tests/test_internal_tx_indexer.py index d4c6175a6..0fb443d35 100644 --- a/safe_transaction_service/history/tests/test_internal_tx_indexer.py +++ b/safe_transaction_service/history/tests/test_internal_tx_indexer.py @@ -8,6 +8,7 @@ from eth_typing import HexStr from safe_eth.eth import EthereumClient from safe_eth.eth.ethereum_client import TracingManager +from safe_eth.util.util import to_0x_hex_str from ..indexers import InternalTxIndexer, InternalTxIndexerProvider from ..indexers.internal_tx_indexer import InternalTxIndexerWithTraceBlock @@ -65,7 +66,7 @@ def return_sorted_blocks(self, hashes: HexStr): :param hashes: :return: """ - block_dict = {block["hash"].hex(): block for block in block_result} + block_dict = {to_0x_hex_str(block["hash"]): block for block in block_result} return [block_dict[provided_hash] for provided_hash in hashes] @mock.patch.object( diff --git a/safe_transaction_service/history/tests/test_migrations.py b/safe_transaction_service/history/tests/test_migrations.py index 894d5a7e6..53a7b51e1 100644 --- a/safe_transaction_service/history/tests/test_migrations.py +++ b/safe_transaction_service/history/tests/test_migrations.py @@ -6,6 +6,7 @@ from django_test_migrations.migrator import Migrator from eth_account import Account from safe_eth.eth.utils import fast_keccak, fast_keccak_text +from safe_eth.util.util import to_0x_hex_str class TestMigrations(TestCase): @@ -53,7 +54,7 @@ def test_migration_forward_0068(self): ] for origin in origins: MultisigTransactionOld.objects.create( - safe_tx_hash=fast_keccak_text(f"multisig-tx-{origin}").hex(), + safe_tx_hash=to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origin}")), safe=Account.create().address, value=0, operation=0, @@ -72,21 +73,21 @@ def test_migration_forward_0068(self): ) # String should keep string - hash = fast_keccak_text(f"multisig-tx-{origins[0]}").hex() + hash = to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origins[0]}")) self.assertEqual(MultisigTransactionNew.objects.get(pk=hash).origin, origins[0]) # String json should be converted to json - hash = fast_keccak_text(f"multisig-tx-{origins[1]}").hex() + hash = to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origins[1]}")) self.assertEqual( MultisigTransactionNew.objects.get(pk=hash).origin, json.loads(origins[1]) ) # Empty string should be empty object - hash = fast_keccak_text(f"multisig-tx-{origins[2]}").hex() + hash = to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origins[2]}")) self.assertEqual(MultisigTransactionNew.objects.get(pk=hash).origin, {}) # None should be empty object - hash = fast_keccak_text(f"multisig-tx-{origins[2]}").hex() + hash = to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origins[2]}")) self.assertEqual(MultisigTransactionNew.objects.get(pk=hash).origin, {}) def test_migration_backward_0068(self): @@ -99,7 +100,7 @@ def test_migration_backward_0068(self): origins = ["{ TestString", {"url": "https://example.com", "name": "app"}, {}] for origin in origins: MultisigTransactionNew.objects.create( - safe_tx_hash=fast_keccak_text(f"multisig-tx-{origin}").hex(), + safe_tx_hash=to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origin}")), safe=Account.create().address, value=0, operation=0, @@ -118,17 +119,17 @@ def test_migration_backward_0068(self): ) # String should keep string - hash = fast_keccak_text(f"multisig-tx-{origins[0]}").hex() + hash = to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origins[0]}")) self.assertEqual(MultisigTransactionOld.objects.get(pk=hash).origin, origins[0]) # Json should be converted to a string json - hash = fast_keccak_text(f"multisig-tx-{origins[1]}").hex() + hash = to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origins[1]}")) self.assertEqual( MultisigTransactionOld.objects.get(pk=hash).origin, json.dumps(origins[1]) ) # Empty object should be None - hash = fast_keccak_text(f"multisig-tx-{origins[2]}").hex() + hash = to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origins[2]}")) self.assertEqual(MultisigTransactionOld.objects.get(pk=hash).origin, None) def test_migration_forward_0069(self): @@ -262,7 +263,7 @@ def test_migration_forward_0073_safe_apps_links(self): MultisigTransaction = new_state.apps.get_model("history", "MultisigTransaction") for origin in origins: MultisigTransaction.objects.create( - safe_tx_hash=fast_keccak_text(f"multisig-tx-{origin}").hex(), + safe_tx_hash=to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origin}")), safe=Account.create().address, value=0, operation=0, @@ -310,7 +311,7 @@ def test_migration_backward_0073_safe_apps_links(self): MultisigTransaction = new_state.apps.get_model("history", "MultisigTransaction") for origin in origins: MultisigTransaction.objects.create( - safe_tx_hash=fast_keccak_text(f"multisig-tx-{origin}").hex(), + safe_tx_hash=to_0x_hex_str(fast_keccak_text(f"multisig-tx-{origin}")), safe=Account.create().address, value=0, operation=0, diff --git a/safe_transaction_service/history/tests/test_models.py b/safe_transaction_service/history/tests/test_models.py index 87b58974a..532749d8b 100644 --- a/safe_transaction_service/history/tests/test_models.py +++ b/safe_transaction_service/history/tests/test_models.py @@ -214,7 +214,7 @@ def test_multisig_transaction_owners(self): self.assertEqual(multisig_transaction.owners, []) account = Account.create() - multisig_transaction.signatures = account.signHash( + multisig_transaction.signatures = account.unsafe_sign_hash( multisig_transaction.safe_tx_hash )["signature"] multisig_transaction.save() diff --git a/safe_transaction_service/history/tests/test_safe_events_indexer.py b/safe_transaction_service/history/tests/test_safe_events_indexer.py index f9624081b..c3fd485a3 100644 --- a/safe_transaction_service/history/tests/test_safe_events_indexer.py +++ b/safe_transaction_service/history/tests/test_safe_events_indexer.py @@ -7,6 +7,7 @@ from safe_eth.eth.contracts import get_safe_V1_3_0_contract, get_safe_V1_4_1_contract from safe_eth.safe import Safe from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin +from safe_eth.util.util import to_0x_hex_str from web3 import Web3 from web3.auto import w3 from web3.datastructures import AttributeDict @@ -139,7 +140,8 @@ def test_invalid_event(self): # Dangling event topic is "supported" self.assertIn( - dangling_event["topics"][0].hex(), self.safe_events_indexer.events_to_listen + to_0x_hex_str(dangling_event["topics"][0]), + self.safe_events_indexer.events_to_listen, ) # Dangling event cannot be decoded @@ -147,7 +149,8 @@ def test_invalid_event(self): # Valid event is supported self.assertIn( - valid_event["topics"][0].hex(), self.safe_events_indexer.events_to_listen + to_0x_hex_str(valid_event["topics"][0]), + self.safe_events_indexer.events_to_listen, ) # Dangling event cannot be decoded, but valid event is @@ -287,7 +290,7 @@ def test_safe_events_indexer(self): self.assertEqual(MultisigTransaction.objects.count(), 1) self.assertEqual( MultisigTransaction.objects.get().safe_tx_hash, - multisig_tx.safe_tx_hash.hex(), + to_0x_hex_str(multisig_tx.safe_tx_hash), ) self.assertEqual(MultisigConfirmation.objects.count(), 1) @@ -323,7 +326,7 @@ def test_safe_events_indexer(self): self.assertEqual(MultisigTransaction.objects.count(), 2) self.assertEqual( MultisigTransaction.objects.order_by("-nonce")[0].safe_tx_hash, - multisig_tx.safe_tx_hash.hex(), + to_0x_hex_str(multisig_tx.safe_tx_hash), ) self.assertEqual(MultisigConfirmation.objects.count(), 2) @@ -371,7 +374,7 @@ def test_safe_events_indexer(self): self.assertEqual(MultisigTransaction.objects.count(), 3) self.assertEqual( MultisigTransaction.objects.order_by("-nonce")[0].safe_tx_hash, - multisig_tx.safe_tx_hash.hex(), + to_0x_hex_str(multisig_tx.safe_tx_hash), ) self.assertEqual(MultisigConfirmation.objects.count(), 4) @@ -408,7 +411,7 @@ def test_safe_events_indexer(self): self.assertEqual(MultisigTransaction.objects.count(), 4) self.assertEqual( MultisigTransaction.objects.order_by("-nonce")[0].safe_tx_hash, - multisig_tx.safe_tx_hash.hex(), + to_0x_hex_str(multisig_tx.safe_tx_hash), ) self.assertEqual(MultisigConfirmation.objects.count(), 5) @@ -464,7 +467,7 @@ def test_safe_events_indexer(self): self.assertEqual(MultisigTransaction.objects.count(), 5) self.assertEqual( MultisigTransaction.objects.order_by("-nonce")[0].safe_tx_hash, - multisig_tx.safe_tx_hash.hex(), + to_0x_hex_str(multisig_tx.safe_tx_hash), ) self.assertEqual(MultisigConfirmation.objects.count(), 6) @@ -500,7 +503,7 @@ def test_safe_events_indexer(self): self.assertEqual(MultisigTransaction.objects.count(), 6) self.assertEqual( MultisigTransaction.objects.order_by("-nonce")[0].safe_tx_hash, - multisig_tx.safe_tx_hash.hex(), + to_0x_hex_str(multisig_tx.safe_tx_hash), ) self.assertEqual(MultisigConfirmation.objects.count(), 7) @@ -515,7 +518,7 @@ def test_safe_events_indexer(self): } ) tx = owner_account_1.sign_transaction(tx) - self.w3.eth.send_raw_transaction(tx["rawTransaction"]) + self.w3.eth.send_raw_transaction(tx["raw_transaction"]) # Process events: ApproveHash self.assertEqual(self.safe_events_indexer.start(), (1, 1)) self.safe_tx_processor.process_decoded_transactions(txs_decoded_queryset.all()) @@ -524,7 +527,7 @@ def test_safe_events_indexer(self): # Check a MultisigConfirmation was created self.assertTrue( MultisigConfirmation.objects.filter( - multisig_transaction_hash=random_hash.hex() + multisig_transaction_hash=to_0x_hex_str(random_hash) ).exists() ) self.assertEqual( @@ -559,7 +562,7 @@ def test_safe_events_indexer(self): self.assertEqual(MultisigTransaction.objects.count(), 7) self.assertEqual( MultisigTransaction.objects.order_by("-nonce")[0].safe_tx_hash, - multisig_tx.safe_tx_hash.hex(), + to_0x_hex_str(multisig_tx.safe_tx_hash), ) self.assertEqual(MultisigConfirmation.objects.count(), 9) @@ -602,7 +605,7 @@ def test_safe_events_indexer(self): self.assertEqual( MultisigTransaction.objects.order_by("-nonce")[0].safe_tx_hash, - multisig_tx.safe_tx_hash.hex(), + to_0x_hex_str(multisig_tx.safe_tx_hash), ) expected_multisig_transactions = 8 expected_multisig_confirmations = 10 @@ -802,7 +805,7 @@ def test_proxy_creation_event_without_initializer(self): {"nonce": self.w3.eth.get_transaction_count(owner_account_1.address)} ) signed_tx = owner_account_1.sign_transaction(setup_call) - tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) + tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction) self.assertEqual(self.safe_events_indexer.start(), (1, 1)) # We remove the proxyCreation internaltx self.assertEqual(InternalTx.objects.count(), 1) @@ -830,7 +833,7 @@ def test_proxy_creation_event_without_initializer(self): {"nonce": self.w3.eth.get_transaction_count(owner_account_1.address)} ) signed_tx = owner_account_1.sign_transaction(setup_call) - tx_hash = w3.eth.send_raw_transaction(signed_tx.rawTransaction) + tx_hash = w3.eth.send_raw_transaction(signed_tx.raw_transaction) self.assertEqual(self.safe_events_indexer.start(), (2, 2)) # Proxy creation InternalTx must contain the Safe address self.assertEqual( diff --git a/safe_transaction_service/history/tests/test_signals.py b/safe_transaction_service/history/tests/test_signals.py index b2b7ba07b..b80c181a2 100644 --- a/safe_transaction_service/history/tests/test_signals.py +++ b/safe_transaction_service/history/tests/test_signals.py @@ -11,6 +11,7 @@ from hexbytes import HexBytes from safe_eth.eth import EthereumNetwork from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin +from safe_eth.util.util import to_0x_hex_str from ...events.services.queue_service import QueueService from ...safe_messages.models import SafeMessage, SafeMessageConfirmation @@ -183,7 +184,9 @@ def test_signals_are_correctly_fired(self, send_event_mock: MagicMock): "type": TransactionServiceEventType.EXECUTED_MULTISIG_TRANSACTION.name, "safeTxHash": multisig_tx.safe_tx_hash, "to": multisig_tx.to, - "data": HexBytes(multisig_tx.data).hex() if multisig_tx.data else None, + "data": ( + to_0x_hex_str(HexBytes(multisig_tx.data)) if multisig_tx.data else None + ), "failed": "false", "txHash": multisig_tx.ethereum_tx_id, "chainId": str(EthereumNetwork.GANACHE.value), diff --git a/safe_transaction_service/history/tests/test_tx_processor.py b/safe_transaction_service/history/tests/test_tx_processor.py index 193354bd8..a05298d82 100644 --- a/safe_transaction_service/history/tests/test_tx_processor.py +++ b/safe_transaction_service/history/tests/test_tx_processor.py @@ -9,6 +9,7 @@ from safe_eth.eth.utils import fast_keccak_text from safe_eth.safe.safe_signature import SafeSignatureType from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.safe_messages.models import SafeMessageConfirmation from safe_transaction_service.safe_messages.tests.factories import ( @@ -354,7 +355,7 @@ def test_tx_processor_with_factory(self): self.assertTrue(multisig_transaction.trusted) # Test ApproveHash. For that we need the `previous_trace` to get the owner - hash_to_approve = keccak(text="HariSeldon").hex() + hash_to_approve = to_0x_hex_str(keccak(text="HariSeldon")) owner_approving = Account.create().address approve_hash_decoded_tx = InternalTxDecodedFactory( function_name="approveHash", @@ -411,7 +412,7 @@ def test_tx_processor_is_failed(self): ethereum_tx = EthereumTxFactory(logs=logs) self.assertTrue(tx_processor.is_failed(ethereum_tx, logs[0]["data"])) self.assertFalse( - tx_processor.is_failed(ethereum_tx, fast_keccak_text("hola").hex()) + tx_processor.is_failed(ethereum_tx, to_0x_hex_str(fast_keccak_text("hola"))) ) # Event for Safes >= 1.1.1 @@ -430,7 +431,7 @@ def test_tx_processor_is_failed(self): ethereum_tx = EthereumTxFactory(logs=logs) self.assertTrue(tx_processor.is_failed(ethereum_tx, safe_tx_hash)) self.assertFalse( - tx_processor.is_failed(ethereum_tx, fast_keccak_text("hola").hex()) + tx_processor.is_failed(ethereum_tx, to_0x_hex_str(fast_keccak_text("hola"))) ) # Event for Safes >= 1.4.1 @@ -449,7 +450,7 @@ def test_tx_processor_is_failed(self): ethereum_tx = EthereumTxFactory(logs=logs) self.assertTrue(tx_processor.is_failed(ethereum_tx, safe_tx_hash)) self.assertFalse( - tx_processor.is_failed(ethereum_tx, fast_keccak_text("hola").hex()) + tx_processor.is_failed(ethereum_tx, to_0x_hex_str(fast_keccak_text("hola"))) ) def test_tx_is_version_breaking_signatures(self): @@ -566,7 +567,7 @@ def test_process_module_tx(self): self.assertEqual(ModuleTransaction.objects.count(), 1) module_tx = ModuleTransaction.objects.get() self.assertEqual( - "0x" + bytes(module_tx.data).hex(), + to_0x_hex_str(bytes(module_tx.data)), module_internal_tx_decoded.arguments["data"], ) self.assertEqual( diff --git a/safe_transaction_service/history/tests/test_views.py b/safe_transaction_service/history/tests/test_views.py index ef0cc3080..a30371403 100644 --- a/safe_transaction_service/history/tests/test_views.py +++ b/safe_transaction_service/history/tests/test_views.py @@ -24,6 +24,7 @@ from safe_eth.safe.safe_signature import SafeSignature, SafeSignatureType from safe_eth.safe.signatures import signature_to_bytes from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.account_abstraction.tests import factories as aa_factories from safe_transaction_service.contracts.models import ContractQuerySet @@ -710,7 +711,7 @@ def test_get_module_transaction(self): "module": module_transaction.module, "to": module_transaction.to, "value": str(module_transaction.value), - "data": module_transaction.data.hex(), + "data": to_0x_hex_str(module_transaction.data), "operation": module_transaction.operation, "dataDecoded": None, "moduleTransactionId": module_transaction_id, @@ -718,7 +719,7 @@ def test_get_module_transaction(self): ) def test_get_multisig_confirmation(self): - random_safe_tx_hash = fast_keccak_text("enxebre").hex() + random_safe_tx_hash = to_0x_hex_str(fast_keccak_text("enxebre")) response = self.client.get( reverse( "v1:history:multisig-transaction-confirmations", @@ -744,11 +745,11 @@ def test_get_multisig_confirmation(self): self.assertEqual(response.data["count"], 2) def test_post_multisig_confirmation(self): - random_safe_tx_hash = fast_keccak_text("enxebre").hex() + random_safe_tx_hash = to_0x_hex_str(fast_keccak_text("enxebre")) data = { - "signature": Account.create() - .signHash(random_safe_tx_hash)["signature"] - .hex() # Not valid signature + "signature": to_0x_hex_str( + Account.create().unsafe_sign_hash(random_safe_tx_hash)["signature"] + ) # Not valid signature } response = self.client.post( reverse( @@ -782,9 +783,9 @@ def test_post_multisig_confirmation(self): random_account = Account.create() data = { - "signature": random_account.signHash(safe_tx_hash)[ - "signature" - ].hex() # Not valid signature + "signature": to_0x_hex_str( + random_account.unsafe_sign_hash(safe_tx_hash)["signature"] + ) # Not valid signature } # Transaction was executed, confirmations cannot be added response = self.client.post( @@ -816,7 +817,11 @@ def test_post_multisig_confirmation(self): response.data["signature"][0], ) - data = {"signature": owner_account_1.signHash(safe_tx_hash)["signature"].hex()} + data = { + "signature": to_0x_hex_str( + owner_account_1.unsafe_sign_hash(safe_tx_hash)["signature"] + ) + } self.assertEqual(MultisigConfirmation.objects.count(), 0) response = self.client.post( reverse( @@ -836,10 +841,10 @@ def test_post_multisig_confirmation(self): # Add multiple signatures data = { - "signature": ( - owner_account_1.signHash(safe_tx_hash)["signature"] - + owner_account_2.signHash(safe_tx_hash)["signature"] - ).hex() + "signature": to_0x_hex_str( + owner_account_1.unsafe_sign_hash(safe_tx_hash)["signature"] + + owner_account_2.unsafe_sign_hash(safe_tx_hash)["signature"] + ) } self.assertEqual(MultisigConfirmation.objects.count(), 1) response = self.client.post( @@ -853,7 +858,7 @@ def test_post_multisig_confirmation(self): self.assertEqual(MultisigConfirmation.objects.count(), 2) def test_get_multisig_transaction(self): - safe_tx_hash = fast_keccak_text("gnosis").hex() + safe_tx_hash = to_0x_hex_str(fast_keccak_text("gnosis")) response = self.client.get( reverse("v1:history:multisig-transaction", args=(safe_tx_hash,)), format="json", @@ -950,7 +955,7 @@ def test_get_multisig_transaction(self): def test_delete_multisig_transaction(self): owner_account = Account.create() - safe_tx_hash = fast_keccak_text("random-tx").hex() + safe_tx_hash = to_0x_hex_str(fast_keccak_text("random-tx")) url = reverse("v1:history:multisig-transaction", args=(safe_tx_hash,)) data = {"signature": "0x" + "1" * (130 * 2)} # 2 signatures of 65 bytes response = self.client.delete(url, format="json", data=data) @@ -1032,9 +1037,9 @@ def test_delete_multisig_transaction(self): multisig_transaction.proposer = owner_account.address multisig_transaction.save(update_fields=["proposer"]) data = { - "signature": owner_account.signHash(safe_tx_hash)[ - "signature" - ].hex() # Random signature + "signature": to_0x_hex_str( + owner_account.unsafe_sign_hash(safe_tx_hash)["signature"] + ) # Random signature } response = self.client.delete(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) @@ -1069,7 +1074,11 @@ def test_delete_multisig_transaction(self): multisig_transaction.proposer = owner_account.address multisig_transaction.proposed_by_delegate = safe_delegate.address multisig_transaction.save(update_fields=["proposer", "proposed_by_delegate"]) - data = {"signature": safe_delegate.signHash(message_hash)["signature"].hex()} + data = { + "signature": to_0x_hex_str( + safe_delegate.unsafe_sign_hash(message_hash)["signature"] + ) + } response = self.client.delete(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertDictEqual( @@ -1089,7 +1098,11 @@ def test_delete_multisig_transaction(self): multisig_transaction.proposer = owner_account.address multisig_transaction.proposed_by_delegate = safe_delegate.address multisig_transaction.save(update_fields=["proposer", "proposed_by_delegate"]) - data = {"signature": safe_delegate.signHash(message_hash)["signature"].hex()} + data = { + "signature": to_0x_hex_str( + safe_delegate.unsafe_sign_hash(message_hash)["signature"] + ) + } response = self.client.delete(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertDictEqual( @@ -1113,7 +1126,11 @@ def test_delete_multisig_transaction(self): multisig_transaction.proposer = owner_account.address multisig_transaction.proposed_by_delegate = safe_delegate.address multisig_transaction.save(update_fields=["proposer", "proposed_by_delegate"]) - data = {"signature": safe_delegate.signHash(message_hash)["signature"].hex()} + data = { + "signature": to_0x_hex_str( + safe_delegate.unsafe_sign_hash(message_hash)["signature"] + ) + } self.assertEqual(MultisigTransaction.objects.count(), 3) self.assertTrue( MultisigTransaction.objects.filter(safe_tx_hash=safe_tx_hash).exists() @@ -1131,7 +1148,11 @@ def test_delete_multisig_transaction(self): ) multisig_transaction.proposer = owner_account.address multisig_transaction.save(update_fields=["proposer"]) - data = {"signature": owner_account.signHash(message_hash)["signature"].hex()} + data = { + "signature": to_0x_hex_str( + owner_account.unsafe_sign_hash(message_hash)["signature"] + ) + } self.assertEqual(MultisigTransaction.objects.count(), 3) self.assertTrue( MultisigTransaction.objects.filter(safe_tx_hash=safe_tx_hash).exists() @@ -1452,7 +1473,7 @@ def test_post_multisig_transactions_null_signature(self): data["refundReceiver"], safe_nonce=data["nonce"], ) - data["contractTransactionHash"] = safe_tx.safe_tx_hash.hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx.safe_tx_hash) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -1512,7 +1533,7 @@ def test_post_multisig_transactions(self): data["refundReceiver"], safe_nonce=data["nonce"], ) - data["contractTransactionHash"] = safe_tx.safe_tx_hash.hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx.safe_tx_hash) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -1536,9 +1557,9 @@ def test_post_multisig_transactions(self): self.assertIsNone(response.data["proposed_by_delegate"]) # Test confirmation with signature - data["signature"] = safe_owner_1.signHash(safe_tx.safe_tx_hash)[ - "signature" - ].hex() + data["signature"] = to_0x_hex_str( + safe_owner_1.unsafe_sign_hash(safe_tx.safe_tx_hash)["signature"] + ) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -1567,9 +1588,9 @@ def test_post_multisig_transactions(self): # Sign with a different user that sender random_user_account = Account.create() - data["signature"] = random_user_account.signHash(safe_tx.safe_tx_hash)[ - "signature" - ].hex() + data["signature"] = to_0x_hex_str( + random_user_account.unsafe_sign_hash(safe_tx.safe_tx_hash)["signature"] + ) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -1633,7 +1654,7 @@ def test_post_multisig_transaction_with_zero_to(self): data["refundReceiver"], safe_nonce=data["nonce"], ) - data["contractTransactionHash"] = safe_tx.safe_tx_hash.hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx.safe_tx_hash) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -1677,7 +1698,9 @@ def test_post_multisig_transaction_with_1271_signature(self): safe_tx_hash_preimage = safe_tx.safe_tx_hash_preimage safe_owner_message_hash = safe_owner.get_message_hash(safe_tx_hash_preimage) - safe_owner_signature = account.signHash(safe_owner_message_hash)["signature"] + safe_owner_signature = account.unsafe_sign_hash(safe_owner_message_hash)[ + "signature" + ] signature_1271 = ( signature_to_bytes( 0, int.from_bytes(HexBytes(safe_owner.address), byteorder="big"), 65 @@ -1685,8 +1708,8 @@ def test_post_multisig_transaction_with_1271_signature(self): + eth_abi.encode(["bytes"], [safe_owner_signature])[32:] ) - data["contractTransactionHash"] = safe_tx_hash.hex() - data["signature"] = signature_1271.hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx_hash) + data["signature"] = to_0x_hex_str(signature_1271) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe.address,)), @@ -1706,7 +1729,7 @@ def test_post_multisig_transaction_with_1271_signature(self): response = self.client.post( reverse( "v1:history:multisig-transaction-confirmations", - args=(safe_tx_hash.hex(),), + args=(to_0x_hex_str(safe_tx_hash),), ), format="json", data=confirmation_data, @@ -1744,7 +1767,7 @@ def test_post_multisig_transaction_with_trusted_user(self): data["refundReceiver"], safe_nonce=data["nonce"], ) - data["contractTransactionHash"] = safe_tx.safe_tx_hash.hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx.safe_tx_hash) factory = APIRequestFactory() request = factory.post( @@ -1827,7 +1850,7 @@ def test_post_multisig_transaction_executed(self): data["refundReceiver"], safe_nonce=data["nonce"], ) - data["contractTransactionHash"] = safe_tx.safe_tx_hash.hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx.safe_tx_hash) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -1872,7 +1895,7 @@ def test_post_multisig_transaction_executed(self): data["refundReceiver"], safe_nonce=data["nonce"], ) - data["contractTransactionHash"] = safe_tx.safe_tx_hash.hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx.safe_tx_hash) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -1899,7 +1922,7 @@ def test_post_multisig_transaction_executed(self): data["refundReceiver"], safe_nonce=data["nonce"], ) - data["contractTransactionHash"] = safe_tx.safe_tx_hash.hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx.safe_tx_hash) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -1949,7 +1972,7 @@ def test_post_multisig_transactions_with_origin(self): data["refundReceiver"], safe_nonce=data["nonce"], ) - data["contractTransactionHash"] = safe_tx.safe_tx_hash.hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx.safe_tx_hash) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -1981,7 +2004,7 @@ def test_post_multisig_transactions_with_origin(self): data["refundReceiver"], safe_nonce=data["nonce"], ) - data["contractTransactionHash"] = safe_tx.safe_tx_hash.hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx.safe_tx_hash) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -2036,13 +2059,15 @@ def test_post_multisig_transactions_with_multiple_signatures(self): safe_nonce=data["nonce"], ) safe_tx_hash = safe_tx.safe_tx_hash - data["contractTransactionHash"] = safe_tx_hash.hex() - data["signature"] = b"".join( - [ - safe_owner.signHash(safe_tx_hash)["signature"] - for safe_owner in safe_owners - ] - ).hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx_hash) + data["signature"] = to_0x_hex_str( + b"".join( + [ + safe_owner.unsafe_sign_hash(safe_tx_hash)["signature"] + for safe_owner in safe_owners + ] + ) + ) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), format="json", @@ -2107,8 +2132,10 @@ def test_post_multisig_transactions_with_delegate(self): safe_nonce=data["nonce"], ) safe_tx_hash = safe_tx.safe_tx_hash - data["contractTransactionHash"] = safe_tx_hash.hex() - data["signature"] = safe_delegate.signHash(safe_tx_hash)["signature"].hex() + data["contractTransactionHash"] = to_0x_hex_str(safe_tx_hash) + data["signature"] = to_0x_hex_str( + safe_delegate.unsafe_sign_hash(safe_tx_hash)["signature"] + ) response = self.client.post( reverse("v1:history:multisig-transactions", args=(safe_address,)), @@ -2303,7 +2330,9 @@ def test_delegates_post(self): # Create delegate self.assertEqual(SafeContractDelegate.objects.count(), 0) hash_to_sign = DelegateSignatureHelper.calculate_hash(delegate.address) - data["signature"] = delegator.signHash(hash_to_sign)["signature"].hex() + data["signature"] = to_0x_hex_str( + delegator.unsafe_sign_hash(hash_to_sign)["signature"] + ) response = self.client.post(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) safe_contract_delegate = SafeContractDelegate.objects.get() @@ -2329,9 +2358,13 @@ def test_delegates_post(self): "label": another_label, "delegate": delegate.address, "delegator": delegator.address, - "signature": delegator.signHash( - DelegateSignatureHelper.calculate_hash(delegate.address, eth_sign=True) - )["signature"].hex(), + "signature": to_0x_hex_str( + delegator.unsafe_sign_hash( + DelegateSignatureHelper.calculate_hash( + delegate.address, eth_sign=True + ) + )["signature"] + ), } response = self.client.post(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) @@ -2341,7 +2374,7 @@ def test_delegates_post(self): signature = signature_to_bytes(0, int(delegator.address, 16), 65) + HexBytes( "0" * 65 ) - data["signature"] = signature.hex() + data["signature"] = to_0x_hex_str(signature) response = self.client.post(url, format="json", data=data) self.assertIn( f"Signature of type=CONTRACT_SIGNATURE for delegator={delegator.address} is not valid", @@ -2444,7 +2477,9 @@ def test_delegate_delete(self): delegate=delegate.address, # random delegator, should not be deleted ) data = { - "signature": signer.signHash(hash_to_sign)["signature"].hex(), + "signature": to_0x_hex_str( + signer.unsafe_sign_hash(hash_to_sign)["signature"] + ), "delegator": delegator.address, } self.assertEqual(SafeContractDelegate.objects.count(), 3) @@ -2469,7 +2504,9 @@ def test_delegate_delete(self): ) signer = Account.create() data = { - "signature": signer.signHash(hash_to_sign)["signature"].hex(), + "signature": to_0x_hex_str( + signer.unsafe_sign_hash(hash_to_sign)["signature"] + ), "delegator": delegator.address, } self.assertEqual(SafeContractDelegate.objects.count(), 1) @@ -2552,7 +2589,9 @@ def test_delete_safe_delegate(self): hash_to_sign = DelegateSignatureHelper.calculate_hash( delegate_address, eth_sign=True ) - data["signature"] = owner_account.signHash(hash_to_sign)["signature"].hex() + data["signature"] = to_0x_hex_str( + owner_account.unsafe_sign_hash(hash_to_sign)["signature"] + ) response = self.client.delete( reverse("v1:history:safe-delegate", args=(safe_address, delegate_address)), format="json", @@ -2567,7 +2606,9 @@ def test_delete_safe_delegate(self): hash_to_sign = DelegateSignatureHelper.calculate_hash( delegate_address, previous_totp=True ) - data["signature"] = owner_account.signHash(hash_to_sign)["signature"].hex() + data["signature"] = to_0x_hex_str( + owner_account.unsafe_sign_hash(hash_to_sign)["signature"] + ) response = self.client.delete( reverse("v1:history:safe-delegate", args=(safe_address, delegate_address)), format="json", @@ -2579,7 +2620,9 @@ def test_delete_safe_delegate(self): ) hash_to_sign = DelegateSignatureHelper.calculate_hash(delegate_address) - data["signature"] = owner_account.signHash(hash_to_sign)["signature"].hex() + data["signature"] = to_0x_hex_str( + owner_account.unsafe_sign_hash(hash_to_sign)["signature"] + ) response = self.client.delete( reverse("v1:history:safe-delegate", args=(safe_address, delegate_address)), format="json", @@ -2612,7 +2655,9 @@ def test_delete_safe_delegate(self): safe_contract=safe_contract, delegate=delegate_account.address ) hash_to_sign = DelegateSignatureHelper.calculate_hash(delegate_account.address) - data["signature"] = delegate_account.signHash(hash_to_sign)["signature"].hex() + data["signature"] = to_0x_hex_str( + delegate_account.unsafe_sign_hash(hash_to_sign)["signature"] + ) response = self.client.delete( reverse( "v1:history:safe-delegate", @@ -3397,7 +3442,7 @@ def test_safe_creation_view(self): ), "paymaster": safe_operation.user_operation.paymaster, "paymaster_data": "0x", - "signature": "0x" + safe_operation.user_operation.signature.hex(), + "signature": to_0x_hex_str(safe_operation.user_operation.signature), "entry_point": safe_operation.user_operation.entry_point, "safe_operation": { "created": datetime_to_str(safe_operation.created), @@ -3407,7 +3452,9 @@ def test_safe_creation_view(self): "valid_until": datetime_to_str(safe_operation.valid_until), "module_address": safe_operation.module_address, "confirmations": [], - "prepared_signature": HexBytes(safe_operation.build_signature()).hex(), + "prepared_signature": to_0x_hex_str( + HexBytes(safe_operation.build_signature()) + ), }, } @@ -3745,7 +3792,7 @@ def test_data_decoder_view(self): response = self.client.post( reverse("v1:history:data-decoder"), format="json", - data={"data": add_owner_with_threshold_data.hex()}, + data={"data": to_0x_hex_str(add_owner_with_threshold_data)}, ) self.assertEqual(response.status_code, status.HTTP_200_OK) diff --git a/safe_transaction_service/history/tests/test_views_v2.py b/safe_transaction_service/history/tests/test_views_v2.py index 52b51ec8b..574bec114 100644 --- a/safe_transaction_service/history/tests/test_views_v2.py +++ b/safe_transaction_service/history/tests/test_views_v2.py @@ -11,6 +11,7 @@ from safe_eth.eth.constants import NULL_ADDRESS from safe_eth.safe.signatures import signature_to_bytes from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin +from safe_eth.util.util import to_0x_hex_str from ...tokens.models import Token from ...utils.utils import datetime_to_str @@ -211,7 +212,9 @@ def test_delegates_post(self): hash_to_sign = DelegateSignatureHelperV2.calculate_hash( delegate.address, chain_id, False ) - data["signature"] = delegator.signHash(hash_to_sign)["signature"].hex() + data["signature"] = to_0x_hex_str( + delegator.unsafe_sign_hash(hash_to_sign)["signature"] + ) response = self.client.post(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) safe_contract_delegate = SafeContractDelegate.objects.get() @@ -250,7 +253,9 @@ def test_delegates_post(self): "label": "Kim Wexler", "delegate": delegate.address, "delegator": delegator.address, - "signature": delegator.signHash(hash_to_sign)["signature"].hex(), + "signature": to_0x_hex_str( + delegator.unsafe_sign_hash(hash_to_sign)["signature"] + ), } response = self.client.post(url, format="json", data=data) self.assertEqual(response.status_code, status.HTTP_201_CREATED) @@ -260,7 +265,7 @@ def test_delegates_post(self): signature = signature_to_bytes(0, int(delegator.address, 16), 65) + HexBytes( "0" * 65 ) - data["signature"] = signature.hex() + data["signature"] = to_0x_hex_str(signature) response = self.client.post(url, format="json", data=data) self.assertIn( f"Signature of type=CONTRACT_SIGNATURE for signer={delegator.address} is not valid", @@ -279,7 +284,9 @@ def test_delegate_creation_without_chain_id(self): "label": "Kim Wexler", "delegate": delegate.address, "delegator": delegator.address, - "signature": delegator.signHash(hash_to_sign)["signature"].hex(), + "signature": to_0x_hex_str( + delegator.unsafe_sign_hash(hash_to_sign)["signature"] + ), } response = self.client.post( @@ -302,7 +309,9 @@ def test_delegate_creation_without_chain_id_with_safe(self): "safe": safe.address, "delegate": delegate.address, "delegator": delegator.address, - "signature": delegator.signHash(hash_to_sign)["signature"].hex(), + "signature": to_0x_hex_str( + delegator.unsafe_sign_hash(hash_to_sign)["signature"] + ), } with mock.patch( @@ -418,7 +427,9 @@ def test_delegate_delete(self): self.assertEqual(SafeContractDelegate.objects.count(), 3) data = { - "signature": signer.signHash(hash_to_sign)["signature"].hex(), + "signature": to_0x_hex_str( + signer.unsafe_sign_hash(hash_to_sign)["signature"] + ), "delegator": delegator.address, } response = self.client.delete( @@ -452,7 +463,9 @@ def test_delegate_delete(self): self.assertEqual(SafeContractDelegate.objects.count(), 2) data = { "safe": safe_address, - "signature": delegator.signHash(hash_to_sign)["signature"].hex(), + "signature": to_0x_hex_str( + delegator.unsafe_sign_hash(hash_to_sign)["signature"] + ), "delegator": delegator.address, } response = self.client.delete( @@ -470,7 +483,9 @@ def test_delegate_delete(self): get_safe_owners_mock.return_value = [delegator.address] data = { "safe": safe_address, - "signature": delegator.signHash(hash_to_sign)["signature"].hex(), + "signature": to_0x_hex_str( + delegator.unsafe_sign_hash(hash_to_sign)["signature"] + ), "delegator": delegator.address, } response = self.client.delete( @@ -484,7 +499,9 @@ def test_delegate_delete(self): # Try an invalid signer signer = Account.create() data = { - "signature": signer.signHash(hash_to_sign)["signature"].hex(), + "signature": to_0x_hex_str( + signer.unsafe_sign_hash(hash_to_sign)["signature"] + ), "delegator": delegator.address, } response = self.client.delete( @@ -497,7 +514,9 @@ def test_delegate_delete(self): ) self.assertEqual(SafeContractDelegate.objects.count(), 1) data = { - "signature": delegator.signHash(hash_to_sign)["signature"].hex(), + "signature": to_0x_hex_str( + delegator.unsafe_sign_hash(hash_to_sign)["signature"] + ), "delegator": delegator.address, } response = self.client.delete( diff --git a/safe_transaction_service/history/utils.py b/safe_transaction_service/history/utils.py index d1a4fc515..f57f33d3b 100644 --- a/safe_transaction_service/history/utils.py +++ b/safe_transaction_service/history/utils.py @@ -7,6 +7,7 @@ from django.utils.translation import gettext as _ from hexbytes import HexBytes +from safe_eth.util.util import to_0x_hex_str from web3.types import LogReceipt @@ -36,7 +37,7 @@ def to_python(self, value: Union[str, bytes, memoryview]) -> HexBytes: return value def prepare_value(self, value: memoryview) -> str: - return "0x" + bytes(value).hex() if value else "" + return to_0x_hex_str(bytes(value)) if value else "" def clean_receipt_log(receipt_log: LogReceipt) -> Optional[Dict[str, Any]]: @@ -49,8 +50,8 @@ def clean_receipt_log(receipt_log: LogReceipt) -> Optional[Dict[str, Any]]: parsed_log = { "address": receipt_log["address"], - "data": receipt_log["data"].hex(), - "topics": [topic.hex() for topic in receipt_log["topics"]], + "data": to_0x_hex_str(receipt_log["data"]), + "topics": [to_0x_hex_str(topic) for topic in receipt_log["topics"]], } return parsed_log diff --git a/safe_transaction_service/notifications/serializers.py b/safe_transaction_service/notifications/serializers.py index 545d845f5..4c9ca1d7e 100644 --- a/safe_transaction_service/notifications/serializers.py +++ b/safe_transaction_service/notifications/serializers.py @@ -122,7 +122,7 @@ def process_parsed_signatures( else: owners_to_not_register.append(owner) # raise ValidationError(f'Owner={owner} is not an owner of any of the safes={data["safes"]}. ' - # f'Expected hash to sign {hash_to_sign.hex()}') + # f'Expected hash to sign {to_0x_hex_str(hash_to_sign)}') return owners_to_register, owners_to_not_register def validate(self, attrs: Dict[str, Any]): diff --git a/safe_transaction_service/notifications/tests/test_tasks.py b/safe_transaction_service/notifications/tests/test_tasks.py index 8226ef82a..7245421e7 100644 --- a/safe_transaction_service/notifications/tests/test_tasks.py +++ b/safe_transaction_service/notifications/tests/test_tasks.py @@ -4,6 +4,7 @@ from eth_account import Account from safe_eth.eth.utils import fast_keccak_text +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.history.models import ( EthereumTxCallType, @@ -91,7 +92,7 @@ def test_send_notification_owner_task(self): safe_address = safe_contract.address threshold = 2 owners = [Account.create().address for _ in range(2)] - safe_tx_hash = fast_keccak_text("hola").hex() + safe_tx_hash = to_0x_hex_str(fast_keccak_text("hola")) with self.assertLogs(logger=task_logger) as cm: self.assertEqual( send_notification_owner_task.delay(safe_address, safe_tx_hash).result, @@ -183,7 +184,7 @@ def test_send_notification_owner_task(self): self.assertIn("does not require more confirmations", cm.output[0]) def test_send_notification_owner_delegate_task(self): - safe_tx_hash = fast_keccak_text("aloha").hex() + safe_tx_hash = to_0x_hex_str(fast_keccak_text("aloha")) safe_contract = SafeContractFactory() safe_address = safe_contract.address safe_status = SafeLastStatusFactory(address=safe_address, threshold=3) @@ -218,7 +219,7 @@ def test_send_notification_owner_delegate_task(self): def test_send_notification_owner_task_called(self): safe_address = Account.create().address - safe_tx_hash = fast_keccak_text("hola").hex() + safe_tx_hash = to_0x_hex_str(fast_keccak_text("hola")) payload = { "address": safe_address, "type": TransactionServiceEventType.PENDING_MULTISIG_TRANSACTION.name, diff --git a/safe_transaction_service/notifications/tests/test_views.py b/safe_transaction_service/notifications/tests/test_views.py index c5bc8c4db..a2af31736 100644 --- a/safe_transaction_service/notifications/tests/test_views.py +++ b/safe_transaction_service/notifications/tests/test_views.py @@ -9,6 +9,7 @@ from rest_framework import status from rest_framework.test import APITestCase from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.history.tests.factories import ( SafeContractDelegateFactory, @@ -131,7 +132,9 @@ def test_notifications_devices_create_with_signatures_view(self): hash_to_sign = calculate_device_registration_hash( timestamp, unique_id, cloud_messaging_token, safes ) - signatures = [owner_account.signHash(hash_to_sign)["signature"].hex()] + signatures = [ + to_0x_hex_str(owner_account.unsafe_sign_hash(hash_to_sign)["signature"]) + ] data = { "uuid": unique_id, "safes": safes, @@ -168,7 +171,11 @@ def test_notifications_devices_create_with_signatures_view(self): ) # Add another signature - signatures.append(owner_account_2.signHash(hash_to_sign)["signature"].hex()) + signatures.append( + to_0x_hex_str( + owner_account_2.unsafe_sign_hash(hash_to_sign)["signature"] + ) + ) response = self.client.post( reverse("v1:notifications:devices"), format="json", data=data ) @@ -215,7 +222,9 @@ def test_notifications_devices_create_with_signatures_eip191_view(self): timestamp, unique_id, cloud_messaging_token, safes ) message_to_sign = encode_defunct(hash_to_sign) - signatures = [owner_account.sign_message(message_to_sign)["signature"].hex()] + signatures = [ + to_0x_hex_str(owner_account.sign_message(message_to_sign)["signature"]) + ] data = { "uuid": unique_id, "safes": safes, @@ -256,7 +265,9 @@ def test_notifications_devices_create_with_delegates_signatures_view(self): hash_to_sign = calculate_device_registration_hash( timestamp, unique_id, cloud_messaging_token, safes ) - signatures = [delegate.signHash(hash_to_sign)["signature"].hex()] + signatures = [ + to_0x_hex_str(delegate.unsafe_sign_hash(hash_to_sign)["signature"]) + ] data = { "uuid": unique_id, "safes": [safe_address], diff --git a/safe_transaction_service/safe_messages/models.py b/safe_transaction_service/safe_messages/models.py index 0687034b1..793b7bf7d 100644 --- a/safe_transaction_service/safe_messages/models.py +++ b/safe_transaction_service/safe_messages/models.py @@ -11,6 +11,7 @@ Keccak256Field, ) from safe_eth.safe.safe_signature import SafeSignatureType +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.utils.constants import SIGNATURE_LENGTH @@ -39,7 +40,7 @@ def __str__(self): message = message_str[:message_size] if len(message_str) > message_size: message += "..." - message_hash = HexBytes(self.message_hash).hex() + message_hash = to_0x_hex_str(HexBytes(self.message_hash)) return f"Safe Message {message_hash} - {message}" def build_signature(self) -> bytes: diff --git a/safe_transaction_service/safe_messages/serializers.py b/safe_transaction_service/safe_messages/serializers.py index a043de225..ba372fb70 100644 --- a/safe_transaction_service/safe_messages/serializers.py +++ b/safe_transaction_service/safe_messages/serializers.py @@ -9,6 +9,7 @@ from safe_eth.eth import get_auto_ethereum_client from safe_eth.eth.eip712 import eip712_encode_hash from safe_eth.safe.safe_signature import SafeSignature, SafeSignatureType +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.utils.serializers import get_safe_owners @@ -40,7 +41,7 @@ def get_valid_owner_from_signatures( for safe_signature in safe_signatures: if not safe_signature.is_valid(ethereum_client, safe_address): raise ValidationError( - f"Signature={safe_signature.signature.hex()} for owner={safe_signature.owner} is not valid" + f"Signature={to_0x_hex_str(safe_signature.signature)} for owner={safe_signature.owner} is not valid" ) owner = safe_signatures[0].owner @@ -108,7 +109,7 @@ def validate(self, attrs): if SafeMessage.objects.filter(message_hash=safe_message_hash).exists(): raise ValidationError( - f"Message with hash {safe_message_hash.hex()} for safe {safe_address} already exists in DB" + f"Message with hash {to_0x_hex_str(safe_message_hash)} for safe {safe_address} already exists in DB" ) safe_signatures = SafeSignature.parse_signature( @@ -218,7 +219,7 @@ def get_prepared_signature(self, obj: SafeMessage) -> Optional[str]: :return: Serialized queryset """ signature = HexBytes(obj.build_signature()) - return HexBytes(signature).hex() if signature else None + return to_0x_hex_str(HexBytes(signature)) if signature else None def get_origin(self, obj: SafeMessage) -> str: return obj.origin if isinstance(obj.origin, str) else json.dumps(obj.origin) diff --git a/safe_transaction_service/safe_messages/tests/factories.py b/safe_transaction_service/safe_messages/tests/factories.py index d63264e04..d117a7817 100644 --- a/safe_transaction_service/safe_messages/tests/factories.py +++ b/safe_transaction_service/safe_messages/tests/factories.py @@ -2,6 +2,7 @@ from eth_account import Account from factory.django import DjangoModelFactory from safe_eth.safe.safe_signature import SafeSignatureType +from safe_eth.util.util import to_0x_hex_str from ..models import SafeMessage, SafeMessageConfirmation from ..utils import get_hash_for_message, get_safe_message_hash_for_message @@ -18,10 +19,12 @@ class Meta: origin = factory.Sequence(lambda n: {"url": f"random-url-{n}"}) @factory.lazy_attribute - def message_hash(self): - return get_safe_message_hash_for_message( - self.safe, get_hash_for_message(self.message) - ).hex() + def message_hash(self) -> str: + return to_0x_hex_str( + get_safe_message_hash_for_message( + self.safe, get_hash_for_message(self.message) + ) + ) class SafeMessageConfirmationFactory(DjangoModelFactory): @@ -34,6 +37,8 @@ class Params: safe_message = factory.SubFactory(SafeMessageFactory) owner = factory.LazyAttribute(lambda o: o.signing_owner.address) signature = factory.LazyAttribute( - lambda o: o.signing_owner.signHash(o.safe_message.message_hash)["signature"] + lambda o: o.signing_owner.unsafe_sign_hash(o.safe_message.message_hash)[ + "signature" + ] ) signature_type = SafeSignatureType.EOA.value diff --git a/safe_transaction_service/safe_messages/tests/test_models.py b/safe_transaction_service/safe_messages/tests/test_models.py index 17b7c7134..5375ea469 100644 --- a/safe_transaction_service/safe_messages/tests/test_models.py +++ b/safe_transaction_service/safe_messages/tests/test_models.py @@ -6,6 +6,7 @@ from eth_account import Account from hexbytes import HexBytes from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin +from safe_eth.util.util import to_0x_hex_str from ..utils import get_hash_for_message, get_safe_message_hash_for_message from .factories import SafeMessageConfirmationFactory, SafeMessageFactory @@ -59,9 +60,11 @@ def test_factory(self): message_hash = safe_message.message_hash self.assertEqual( message_hash, - get_safe_message_hash_for_message( - safe_message.safe, get_hash_for_message(message) - ).hex(), + to_0x_hex_str( + get_safe_message_hash_for_message( + safe_message.safe, get_hash_for_message(message) + ) + ), ) recovered_owner = Account._recover_hash( safe_message.message_hash, diff --git a/safe_transaction_service/safe_messages/tests/test_views.py b/safe_transaction_service/safe_messages/tests/test_views.py index 6f69ea868..c5aab2c06 100644 --- a/safe_transaction_service/safe_messages/tests/test_views.py +++ b/safe_transaction_service/safe_messages/tests/test_views.py @@ -16,6 +16,7 @@ from safe_eth.safe.safe_signature import SafeSignatureEOA from safe_eth.safe.signatures import signature_to_bytes from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin +from safe_eth.util.util import to_0x_hex_str from safe_transaction_service.safe_messages.models import ( SafeMessage, @@ -84,13 +85,13 @@ def test_safe_message_view(self): "proposedBy": safe_message.proposed_by, "safeAppId": safe_message.safe_app_id, "origin": json.dumps(safe_message.origin), - "preparedSignature": safe_message_confirmation.signature.hex(), + "preparedSignature": to_0x_hex_str(safe_message_confirmation.signature), "confirmations": [ { "created": datetime_to_str(safe_message_confirmation.created), "modified": datetime_to_str(safe_message_confirmation.modified), "owner": safe_message_confirmation.owner, - "signature": safe_message_confirmation.signature.hex(), + "signature": to_0x_hex_str(safe_message_confirmation.signature), "signatureType": "EOA", } ], @@ -121,13 +122,13 @@ def test_safe_message_not_camel_case_view(self): "proposedBy": safe_message.proposed_by, "safeAppId": safe_message.safe_app_id, "origin": json.dumps(safe_message.origin), - "preparedSignature": safe_message_confirmation.signature.hex(), + "preparedSignature": to_0x_hex_str(safe_message_confirmation.signature), "confirmations": [ { "created": datetime_to_str(safe_message_confirmation.created), "modified": datetime_to_str(safe_message_confirmation.modified), "owner": safe_message_confirmation.owner, - "signature": safe_message_confirmation.signature.hex(), + "signature": to_0x_hex_str(safe_message_confirmation.signature), "signatureType": "EOA", } ], @@ -151,7 +152,7 @@ def test_safe_messages_create_view(self, get_owners_mock: MagicMock): safe.get_message_hash(message_hash) for message_hash in message_hashes ] signatures = [ - account.signHash(safe_message_hash)["signature"].hex() + to_0x_hex_str(account.unsafe_sign_hash(safe_message_hash)["signature"]) for safe_message_hash in safe_message_hashes ] @@ -255,7 +256,7 @@ def test_safe_messages_create_view(self, get_owners_mock: MagicMock): { "non_field_errors": [ ErrorDetail( - string=f"Message with hash {safe_message_hash.hex()} for safe {safe_address} already exists in DB", + string=f"Message with hash {to_0x_hex_str(safe_message_hash)} for safe {safe_address} already exists in DB", code="invalid", ) ] @@ -272,7 +273,9 @@ def test_safe_messages_create_using_1271_signature_view(self): description = "Testing EIP712 message signing" message_hash = eip712_encode_hash(message) safe_owner_message_hash = safe_owner.get_message_hash(message_hash) - safe_owner_signature = account.signHash(safe_owner_message_hash)["signature"] + safe_owner_signature = account.unsafe_sign_hash(safe_owner_message_hash)[ + "signature" + ] # Build EIP1271 signature v=0 r=safe v=dynamic_part dynamic_part=size+owner_signature signature_1271 = ( @@ -285,7 +288,7 @@ def test_safe_messages_create_using_1271_signature_view(self): data = { "message": message, "description": description, - "signature": HexBytes(signature_1271).hex(), + "signature": to_0x_hex_str(HexBytes(signature_1271)), } response = self.client.post( reverse("v1:safe_messages:safe-messages", args=(safe_address,)), @@ -337,7 +340,7 @@ def test_safe_message_add_signature_view(self, get_owners_mock: MagicMock): ) # Test same signature - data["signature"] = safe_message_confirmation.signature.hex() + data["signature"] = to_0x_hex_str(safe_message_confirmation.signature) response = self.client.post( reverse("v1:safe_messages:signatures", args=(safe_message.message_hash,)), format="json", @@ -358,9 +361,9 @@ def test_safe_message_add_signature_view(self, get_owners_mock: MagicMock): # Test not existing owner owner_account = Account.create() - data["signature"] = owner_account.signHash(safe_message.message_hash)[ - "signature" - ].hex() + data["signature"] = to_0x_hex_str( + owner_account.unsafe_sign_hash(safe_message.message_hash)["signature"] + ) response = self.client.post( reverse("v1:safe_messages:signatures", args=(safe_message.message_hash,)), format="json", @@ -470,7 +473,9 @@ def test_safe_messages_list_view(self): "proposedBy": safe_message.proposed_by, "safeAppId": safe_message.safe_app_id, "origin": json.dumps(safe_message.origin), - "preparedSignature": safe_message_confirmation.signature.hex(), + "preparedSignature": to_0x_hex_str( + safe_message_confirmation.signature + ), "confirmations": [ { "created": datetime_to_str( @@ -480,7 +485,9 @@ def test_safe_messages_list_view(self): safe_message_confirmation.modified ), "owner": safe_message_confirmation.owner, - "signature": safe_message_confirmation.signature.hex(), + "signature": to_0x_hex_str( + safe_message_confirmation.signature + ), "signatureType": "EOA", } ], @@ -518,7 +525,9 @@ def test_safe_messages_list_not_camel_case_view(self): "proposedBy": safe_message.proposed_by, "safeAppId": safe_message.safe_app_id, "origin": json.dumps(safe_message.origin), - "preparedSignature": safe_message_confirmation.signature.hex(), + "preparedSignature": to_0x_hex_str( + safe_message_confirmation.signature + ), "confirmations": [ { "created": datetime_to_str( @@ -528,7 +537,9 @@ def test_safe_messages_list_not_camel_case_view(self): safe_message_confirmation.modified ), "owner": safe_message_confirmation.owner, - "signature": safe_message_confirmation.signature.hex(), + "signature": to_0x_hex_str( + safe_message_confirmation.signature + ), "signatureType": "EOA", } ], @@ -588,13 +599,13 @@ def test_safe_message_view_v1_1_1(self): "proposedBy": safe_message.proposed_by, "safeAppId": safe_message.safe_app_id, "origin": json.dumps(safe_message.origin), - "preparedSignature": safe_message_confirmation.signature.hex(), + "preparedSignature": to_0x_hex_str(safe_message_confirmation.signature), "confirmations": [ { "created": datetime_to_str(safe_message_confirmation.created), "modified": datetime_to_str(safe_message_confirmation.modified), "owner": safe_message_confirmation.owner, - "signature": safe_message_confirmation.signature.hex(), + "signature": to_0x_hex_str(safe_message_confirmation.signature), "signatureType": "EOA", } ], diff --git a/scripts/benchmark_keccak.py b/scripts/benchmark_keccak.py index 9b8d82c3d..2beee628a 100644 --- a/scripts/benchmark_keccak.py +++ b/scripts/benchmark_keccak.py @@ -3,15 +3,16 @@ import sha3 from Crypto.Hash import keccak as crypto_keccak from eth_hash.auto import keccak as eth_hash_keccak +from safe_eth.util.util import to_0x_hex_str from web3 import Web3 def eth_hash_benchmark() -> str: - return eth_hash_keccak(os.urandom(32)).hex() + return to_0x_hex_str(eth_hash_keccak(os.urandom(32))) def web3_benchmark() -> str: - return Web3.keccak(os.urandom(32)).hex() + return to_0x_hex_str(Web3.keccak(os.urandom(32))) def cryptodome_benchmark() -> str: