Skip to content

Commit 1c85ea2

Browse files
committed
fix: .to_message() on Arrays
Related issue: ConsenSysMesh/py-eip712-structs#16 Original patch by @josh-davis-vicinft on ConsenSysMesh/py-eip712-structs#17.
1 parent 5195fb3 commit 1c85ea2

File tree

2 files changed

+41
-10
lines changed

2 files changed

+41
-10
lines changed

src/eip712_structs/struct.py

+18-9
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,14 @@ def data_dict(self) -> dict:
8383
8484
Nested structs instances are also converted to dict form.
8585
"""
86-
return {k: v.data_dict() if isinstance(v, EIP712Struct) else v for k, v in self.values.items()}
86+
return {
87+
k: v.data_dict()
88+
if isinstance(v, EIP712Struct)
89+
else [e.data_dict() for e in v]
90+
if isinstance(v, list) and len(v) and isinstance(v[0], EIP712Struct)
91+
else v
92+
for k, v in self.values.items()
93+
}
8794

8895
@classmethod
8996
def encode_type(cls, resolve: bool = True) -> str:
@@ -95,7 +102,7 @@ def encode_type(cls, resolve: bool = True) -> str:
95102
struct_sig = f"{cls.type_name}({','.join(member_sigs)})"
96103

97104
if resolve:
98-
reference_structs: set[EIP712Struct] = set()
105+
reference_structs: list[EIP712Struct] = []
99106
cls.gather_reference_structs(reference_structs)
100107
sorted_structs = sorted((s for s in reference_structs if s != cls), key=lambda s: s.type_name)
101108
for struct in sorted_structs:
@@ -104,15 +111,17 @@ def encode_type(cls, resolve: bool = True) -> str:
104111
return struct_sig
105112

106113
@classmethod
107-
def gather_reference_structs(cls, struct_set: set[EIP712Struct]) -> None:
114+
def gather_reference_structs(cls, struct_lst: list[EIP712Struct]) -> None:
108115
"""Finds reference structs defined in this struct type, and inserts them into the given set."""
109-
structs: list[EIP712Struct] = [
110-
m[1] for m in cls.get_members() if isinstance(m[1], type) and issubclass(m[1], EIP712Struct)
116+
structs = [m[1] for m in cls.get_members() if isinstance(m[1], type) and issubclass(m[1], EIP712Struct)] + [
117+
m[1].member_type
118+
for m in cls.get_members()
119+
if isinstance(m[1], Array) and hasattr(m[1].member_type, "encode_type")
111120
]
112121
for struct in structs:
113-
if struct not in struct_set:
114-
struct_set.add(struct)
115-
struct.gather_reference_structs(struct_set)
122+
if struct not in struct_lst:
123+
struct_lst.append(struct) # type: ignore[arg-type]
124+
struct.gather_reference_structs(struct_lst) # type: ignore[union-attr]
116125

117126
@classmethod
118127
def type_hash(cls) -> bytes:
@@ -159,7 +168,7 @@ def to_message(self, domain: EIP712Struct | None = None) -> dict:
159168
:returns: This struct + the domain in dict form, structured as specified for EIP712 messages.
160169
"""
161170
domain = self._assert_domain(domain)
162-
structs = {domain, self}
171+
structs = [domain, self]
163172
self.gather_reference_structs(structs)
164173

165174
# Build type dictionary

src/tests/unit/test_message_json.py

+23-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
import os
33

44
import pytest
5-
from eip712_structs import Bytes, EIP712Struct, String, make_domain
5+
from eip712_structs import Array, Bytes, EIP712Struct, String, make_domain
66

77

88
def test_flat_struct_to_message():
@@ -151,3 +151,25 @@ class UnserializableObject:
151151
foo.values["b"] = obj
152152
with pytest.raises(TypeError, match="not JSON serializable"):
153153
foo.to_message_json(domain)
154+
155+
156+
def test_array_to_message():
157+
class TestStruct(EIP712Struct):
158+
byte_array = Array(Bytes(32), 4)
159+
160+
byte_array = [os.urandom(32) for _ in range(4)]
161+
162+
domain = make_domain(name="hello")
163+
s = TestStruct(byte_array=byte_array)
164+
165+
msg = s.to_message(domain)
166+
assert msg["primaryType"] == "TestStruct"
167+
assert msg["types"] == {
168+
"EIP712Domain": [{"name": "name", "type": "string"}],
169+
"TestStruct": [{"name": "byte_array", "type": "bytes32[4]"}],
170+
}
171+
assert msg["domain"] == {"name": "hello"}
172+
assert msg["message"]["byte_array"]
173+
assert isinstance(msg["message"]["byte_array"], list)
174+
assert isinstance(msg["message"]["byte_array"][0], bytes)
175+
assert isinstance(msg["message"]["byte_array"][-1], bytes)

0 commit comments

Comments
 (0)