Skip to content

Commit dbd1950

Browse files
committed
Fix 1271 contract signatures
- Closes #2535 and #2526
1 parent ac49e26 commit dbd1950

File tree

5 files changed

+49
-32
lines changed

5 files changed

+49
-32
lines changed

safe_transaction_service/safe_messages/serializers.py

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
from safe_transaction_service.utils.serializers import get_safe_owners
1717

1818
from .models import SIGNATURE_LENGTH, SafeMessage, SafeMessageConfirmation
19-
from .utils import get_hash_for_message, get_safe_message_hash_for_message
19+
from .utils import (
20+
get_message_encoded,
21+
get_safe_message_hash_for_message,
22+
)
2023

2124

2225
# Request serializers
@@ -105,12 +108,12 @@ def validate_message(self, value: Union[str, dict[str, Any]]):
105108
def validate(self, attrs):
106109
attrs = super().validate(attrs)
107110
safe_address = self.context["safe_address"]
111+
attrs["safe"] = safe_address
108112
message = attrs["message"]
109113
signature = attrs["signature"]
110-
attrs["safe"] = safe_address
111-
message_hash = get_hash_for_message(message)
114+
message_encoded = get_message_encoded(message)
112115
safe_message_hash = get_safe_message_hash_for_message(
113-
safe_address, message_hash
116+
safe_address, message_encoded
114117
)
115118
attrs["message_hash"] = safe_message_hash
116119

@@ -120,7 +123,7 @@ def validate(self, attrs):
120123
)
121124

122125
safe_signatures = SafeSignature.parse_signature(
123-
signature, safe_message_hash, safe_hash_preimage=message_hash
126+
signature, safe_message_hash, safe_hash_preimage=message_encoded
124127
)
125128
owner, signature_type = self.get_valid_owner_from_signatures(
126129
safe_signatures, safe_address, None
@@ -158,11 +161,11 @@ def validate(self, attrs):
158161
attrs["safe_message"] = safe_message
159162
signature: HexStr = attrs["signature"]
160163
safe_address = safe_message.safe
161-
message_hash = get_hash_for_message(safe_message.message)
164+
message_encoded = get_message_encoded(safe_message.message)
162165
safe_message_hash = safe_message.message_hash
163166

164167
safe_signatures = SafeSignature.parse_signature(
165-
signature, safe_message_hash, safe_hash_preimage=message_hash
168+
signature, safe_message_hash, safe_hash_preimage=message_encoded
166169
)
167170
owner, signature_type = self.get_valid_owner_from_signatures(
168171
safe_signatures, safe_address, safe_message

safe_transaction_service/safe_messages/tests/factories.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from safe_eth.util.util import to_0x_hex_str
66

77
from ..models import SafeMessage, SafeMessageConfirmation
8-
from ..utils import get_hash_for_message, get_safe_message_hash_for_message
8+
from ..utils import get_message_encoded, get_safe_message_hash_for_message
99

1010

1111
class SafeMessageFactory(DjangoModelFactory):
@@ -22,7 +22,7 @@ class Meta:
2222
def message_hash(self) -> str:
2323
return to_0x_hex_str(
2424
get_safe_message_hash_for_message(
25-
self.safe, get_hash_for_message(self.message)
25+
self.safe, get_message_encoded(self.message)
2626
)
2727
)
2828

safe_transaction_service/safe_messages/tests/test_models.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin
99
from safe_eth.util.util import to_0x_hex_str
1010

11-
from ..utils import get_hash_for_message, get_safe_message_hash_for_message
11+
from ..utils import get_message_encoded, get_safe_message_hash_for_message
1212
from .factories import SafeMessageConfirmationFactory, SafeMessageFactory
1313
from .mocks import get_eip712_payload_mock
1414

@@ -22,15 +22,15 @@ def test_str(self):
2222
for input, expected in [
2323
(
2424
"TestMessage",
25-
"Safe Message 0xb04a24aa07a51d1d8c3913e9493b3b1f88ed6a8a75430a9a8eda3ed3ce1897bc - TestMessage",
25+
"Safe Message 0x95a89792bad17115e101b4d8fbdcd517dd13d085e815287d7fe791078182bf9e - TestMessage",
2626
),
2727
(
2828
"TestMessageVeryLong",
29-
"Safe Message 0xe3db816540ce371e2703b8ec59bdd6fec32e0c6078f2e204a205fd6d81564f28 - TestMessageVery...",
29+
"Safe Message 0xb7783fde9060e75b61298c14cbc2a987f0e0800d1bb08b4a2b24ce3544b9b144 - TestMessageVery...",
3030
),
3131
(
3232
get_eip712_payload_mock(),
33-
"Safe Message 0xbabb22f5c02a24db447b8f0136d6e26bb58cd6d068ebe8ab25c2221cfdf53e18 - {'types': {'EIP...",
33+
"Safe Message 0x632db20317ce8e467d17e941d209fc1173ff1cad83b0c072c008385a566ddd80 - {'types': {'EIP...",
3434
),
3535
]:
3636
with self.subTest(input=input):
@@ -62,7 +62,7 @@ def test_factory(self):
6262
message_hash,
6363
to_0x_hex_str(
6464
get_safe_message_hash_for_message(
65-
safe_message.safe, get_hash_for_message(message)
65+
safe_message.safe, get_message_encoded(message)
6666
)
6767
),
6868
)

safe_transaction_service/safe_messages/tests/test_views.py

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,11 @@
77

88
import eth_abi
99
from eth_account import Account
10-
from eth_account.messages import defunct_hash_message
1110
from hexbytes import HexBytes
1211
from rest_framework import status
1312
from rest_framework.exceptions import ErrorDetail
1413
from rest_framework.test import APITestCase
15-
from safe_eth.eth.eip712 import eip712_encode_hash
14+
from safe_eth.eth.eip712 import eip712_encode
1615
from safe_eth.safe.safe_signature import SafeSignatureEOA
1716
from safe_eth.safe.signatures import signature_to_bytes
1817
from safe_eth.safe.tests.safe_test_case import SafeTestCaseMixin
@@ -28,6 +27,7 @@
2827
)
2928
from safe_transaction_service.utils.utils import datetime_to_str
3029

30+
from ..utils import encode_eip191_message, encode_eip712_message
3131
from .mocks import get_eip712_payload_mock
3232

3333
logger = logging.getLogger(__name__)
@@ -144,12 +144,13 @@ def test_safe_messages_create_view(self, get_owners_mock: MagicMock):
144144
safe_address = safe.address
145145
messages = ["Text to sign message", get_eip712_payload_mock()]
146146
description = "Testing EIP191 message signing"
147-
message_hashes = [
148-
defunct_hash_message(text=messages[0]),
149-
eip712_encode_hash(messages[1]),
147+
messages_encoded = [
148+
encode_eip191_message(messages[0]),
149+
encode_eip712_message(messages[1]),
150150
]
151151
safe_message_hashes = [
152-
safe.get_message_hash(message_hash) for message_hash in message_hashes
152+
safe.get_message_hash(message_encoded)
153+
for message_encoded in messages_encoded
153154
]
154155
signatures = [
155156
to_0x_hex_str(account.unsafe_sign_hash(safe_message_hash)["signature"])
@@ -158,15 +159,14 @@ def test_safe_messages_create_view(self, get_owners_mock: MagicMock):
158159

159160
sub_tests = ["create_eip191", "create_eip712"]
160161

161-
for sub_test, message, message_hash, safe_message_hash, signature in zip(
162-
sub_tests, messages, message_hashes, safe_message_hashes, signatures
162+
for sub_test, message, safe_message_hash, signature in zip(
163+
sub_tests, messages, safe_message_hashes, signatures
163164
):
164165
SafeMessage.objects.all().delete()
165166
get_owners_mock.return_value = []
166167
with self.subTest(
167168
sub_test,
168169
message=message,
169-
message_hash=message_hash,
170170
safe_message_hash=safe_message_hash,
171171
signature=signature,
172172
):
@@ -289,8 +289,8 @@ def _test_safe_messages_create_using_1271_signature_view(self, safe_deployment_f
289289
safe_address = safe.address
290290
message = get_eip712_payload_mock()
291291
description = "Testing EIP712 message signing"
292-
message_hash = eip712_encode_hash(message)
293-
safe_owner_message_hash = safe_owner.get_message_hash(message_hash)
292+
message_encoded = b"".join(eip712_encode(message))
293+
safe_owner_message_hash = safe_owner.get_message_hash(message_encoded)
294294
safe_owner_signature = account.unsafe_sign_hash(safe_owner_message_hash)[
295295
"signature"
296296
]
Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,36 @@
11
from typing import Any
22

3-
from eth_account.messages import defunct_hash_message
3+
from eth_account.messages import encode_defunct
44
from eth_typing import ChecksumAddress, Hash32
55
from safe_eth.eth import get_auto_ethereum_client
6-
from safe_eth.eth.eip712 import eip712_encode_hash
6+
from safe_eth.eth.eip712 import eip712_encode
77
from safe_eth.safe import Safe
88

99

10-
def get_hash_for_message(message: str | dict[str, Any]) -> Hash32:
10+
def encode_eip191_message(message: str) -> bytes:
11+
signable_message = encode_defunct(text=message)
1112
return (
12-
defunct_hash_message(text=message)
13+
b"\x19"
14+
+ signable_message.version
15+
+ signable_message.header
16+
+ signable_message.body
17+
)
18+
19+
20+
def encode_eip712_message(message: dict[str, Any]) -> bytes:
21+
return b"".join(eip712_encode(message))
22+
23+
24+
def get_message_encoded(message: str | dict[str, Any]) -> bytes:
25+
return (
26+
encode_eip191_message(message)
1327
if isinstance(message, str)
14-
else eip712_encode_hash(message)
28+
else encode_eip712_message(message)
1529
)
1630

1731

1832
def get_safe_message_hash_for_message(
19-
safe_address: ChecksumAddress, message_hash: Hash32
33+
safe_address: ChecksumAddress, message: bytes
2034
) -> Hash32:
2135
safe = Safe(safe_address, get_auto_ethereum_client())
22-
return safe.get_message_hash(message_hash)
36+
return safe.get_message_hash(message)

0 commit comments

Comments
 (0)