From d305f1f5304e1f48ed01836f91735194ffdbe354 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mois=C3=A9s=20Fern=C3=A1ndez?= Date: Tue, 10 Jan 2023 12:26:53 +0100 Subject: [PATCH] Add EIP712 support for bytes and uint formatted as string (#427) --- gnosis/eth/eip712/__init__.py | 8 ++ gnosis/eth/tests/eip712/test_eip712.py | 127 +++++++++++++++++-------- 2 files changed, 94 insertions(+), 41 deletions(-) diff --git a/gnosis/eth/eip712/__init__.py b/gnosis/eth/eip712/__init__.py index 17ea2aea5..eef1797f5 100644 --- a/gnosis/eth/eip712/__init__.py +++ b/gnosis/eth/eip712/__init__.py @@ -57,6 +57,14 @@ def _encode_field(name, typ, value): if value is None: raise Exception(f"Missing value for field {name} of type {type}") + # Accept string bytes + if "bytes" in typ and isinstance(value, str): + value = bytes.fromhex(value.replace("0x", "")) + + # Accept string uint + if "uint" in typ and isinstance(value, str): + value = int(value) + if typ == "bytes": return ["bytes32", fast_keccak(value)] diff --git a/gnosis/eth/tests/eip712/test_eip712.py b/gnosis/eth/tests/eip712/test_eip712.py index 446466fc4..b6874318c 100644 --- a/gnosis/eth/tests/eip712/test_eip712.py +++ b/gnosis/eth/tests/eip712/test_eip712.py @@ -4,6 +4,43 @@ class TestEIP712(TestCase): + address = "0x8e12f01dae5fe7f1122dc42f2cb084f2f9e8aa03" + types = { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + {"name": "version", "type": "string"}, + {"name": "chainId", "type": "uint256"}, + {"name": "verifyingContract", "type": "address"}, + ], + "Mailbox": [ + {"name": "owner", "type": "address"}, + {"name": "messages", "type": "Message[]"}, + ], + "Message": [ + {"name": "sender", "type": "address"}, + {"name": "subject", "type": "string"}, + {"name": "isSpam", "type": "bool"}, + {"name": "body", "type": "string"}, + ], + } + + msgs = [ + { + "sender": address, + "subject": "Hello World", + "body": "The sparrow flies at midnight.", + "isSpam": False, + }, + { + "sender": address, + "subject": "You may have already Won! :dumb-emoji:", + "body": "Click here for sweepstakes!", + "isSpam": True, + }, + ] + + mailbox = {"owner": address, "messages": msgs} + def test_eip712_encode_hash(self): for value in [ {}, @@ -12,8 +49,6 @@ def test_eip712_encode_hash(self): with self.assertRaises(ValueError): eip712_encode_hash(value) - address = "0x8e12f01dae5fe7f1122dc42f2cb084f2f9e8aa03" - wrong_types = { "EIP712Domain": [ {"name": "name", "type": "stringa"}, @@ -33,42 +68,6 @@ def test_eip712_encode_hash(self): ], } - types = { - "EIP712Domain": [ - {"name": "name", "type": "string"}, - {"name": "version", "type": "string"}, - {"name": "chainId", "type": "uint256"}, - {"name": "verifyingContract", "type": "address"}, - ], - "Mailbox": [ - {"name": "owner", "type": "address"}, - {"name": "messages", "type": "Message[]"}, - ], - "Message": [ - {"name": "sender", "type": "address"}, - {"name": "subject", "type": "string"}, - {"name": "isSpam", "type": "bool"}, - {"name": "body", "type": "string"}, - ], - } - - msgs = [ - { - "sender": address, - "subject": "Hello World", - "body": "The sparrow flies at midnight.", - "isSpam": False, - }, - { - "sender": address, - "subject": "You may have already Won! :dumb-emoji:", - "body": "Click here for sweepstakes!", - "isSpam": True, - }, - ] - - mailbox = {"owner": address, "messages": msgs} - payload = { "types": wrong_types, "primaryType": "Mailbox", @@ -76,16 +75,62 @@ def test_eip712_encode_hash(self): "name": "MyDApp", "version": "3.0", "chainId": 41, - "verifyingContract": address, + "verifyingContract": self.address, }, - "message": mailbox, + "message": self.mailbox, } with self.assertRaises(ValueError): eip712_encode_hash(payload) - payload["types"] = types + payload["types"] = self.types self.assertEqual( eip712_encode_hash(payload), b"\xd5N\xcbf7\xfa\x99\n\xae\x02\x86\xd4 \xacpe\x8d\xb9\x95\xaem\t\xcc\x9b\xb1\xda\xcf6J\x14\x17\xd0", ) + + def test_eip712_encode_hash_string_uint(self): + # test string uint (chainId) + payload = { + "types": self.types, + "primaryType": "Mailbox", + "domain": { + "name": "MyDApp", + "version": "3.0", + "chainId": "41", + "verifyingContract": self.address, + }, + "message": self.mailbox, + } + + self.assertEqual( + eip712_encode_hash(payload), + b"\xd5N\xcbf7\xfa\x99\n\xae\x02\x86\xd4 \xacpe\x8d\xb9\x95\xaem\t\xcc\x9b\xb1\xda\xcf6J\x14\x17\xd0", + ) + + def test_eip712_encode_hash_string_bytes(self): + types_with_bytes = { + "EIP712Domain": [ + {"name": "name", "type": "string"}, + ], + "Message": [ + {"name": "oneByte", "type": "bytes1"}, + {"name": "maxByte", "type": "bytes32"}, + ], + } + payload = { + "types": types_with_bytes, + "primaryType": "Message", + "domain": { + "name": "MyDApp", + }, + "message": { + "oneByte": "0x01", + "maxByte": "0x6214da6089b8d8aaa6e6268977746aa0af19fd1ef5d56e225bb3390a697c3ec1", + }, + } + + self.assertEqual( + eip712_encode_hash(payload).hex(), + "2950cf06416c6c20059f24a965e3baf51a24f4ef49a1e7b1a47ee13ee08cde1f", + )