Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support string revision 1 in TypedData #1381

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
a306027
Handle rev 1 string in `TypedData._encode_value()`
franciszekjob Jun 27, 2024
65d34fd
Add typed data rev 1 basic types example; Add tests
franciszekjob Jun 27, 2024
004e03c
Format
franciszekjob Jun 27, 2024
a3769c5
Merge branch 'franciszekjob/1353-5-int-basic-types' of https://github…
franciszekjob Jun 28, 2024
3dd8aeb
Keep `TypedData` dataclass frozen; Use byte array serializer as class…
franciszekjob Jun 28, 2024
c7ec994
Merge branch 'franciszekjob/1353-5-int-basic-types' of https://github…
franciszekjob Jun 28, 2024
94909cb
Merge branch 'franciszekjob/1353-5-int-basic-types' of https://github…
franciszekjob Jun 28, 2024
e4029bf
Merge branch 'franciszekjob/1353-5-int-basic-types' of https://github…
franciszekjob Jun 28, 2024
a55c1d5
Merge branch 'franciszekjob/1353-5-int-basic-types' of https://github…
franciszekjob Jun 28, 2024
45a19c2
Restore previous approach of storing byte array serializer in `TypedD…
franciszekjob Jun 28, 2024
5fdfd7a
Merge branch 'franciszekjob/1353-5-int-basic-types' of https://github…
franciszekjob Jun 28, 2024
a4206d4
Merge branch 'franciszekjob/1353-5-int-basic-types' of https://github…
franciszekjob Jul 1, 2024
632f2d3
Merge branch 'franciszekjob/1353-5-int-basic-types' of https://github…
franciszekjob Jul 1, 2024
f2cd933
Merge branch 'franciszekjob/1353-5-int-basic-types' of https://github…
franciszekjob Jul 1, 2024
30dfa9a
Remove unnecessary dataclass annotation
franciszekjob Jul 1, 2024
53d6a76
Rename `_prepare_long_string()` to `_encode_long_string()`
franciszekjob Jul 2, 2024
acb5c34
Merge branch 'franciszekjob/1353-5-int-basic-types' of https://github…
franciszekjob Jul 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
{
"types": {
"StarknetDomain": [
{ "name": "name", "type": "shortstring" },
{ "name": "version", "type": "shortstring" },
{ "name": "chainId", "type": "shortstring" },
{ "name": "revision", "type": "shortstring" }
],
"Example": [
{ "name": "n0", "type": "felt" },
{ "name": "n1", "type": "bool" },
{ "name": "n2", "type": "string" },
{ "name": "n3", "type": "selector" },
{ "name": "n4", "type": "u128" },
{ "name": "n5", "type": "i128" },
{ "name": "n6", "type": "ContractAddress" },
{ "name": "n7", "type": "ClassHash" },
{ "name": "n8", "type": "timestamp" },
{ "name": "n9", "type": "shortstring" }
]
},
"primaryType": "Example",
"domain": {
"name": "StarkNet Mail",
"version": "1",
"chainId": "1",
"revision": "1"
},
"message": {
"n0": "0x3e8",
"n1": true,
"n2": "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
"n3": "transfer",
"n4": "0x3e8",
"n5": "-170141183460469231731687303715884105727",
"n6": "0x3e8",
"n7": "0x3e8",
"n8": 1000,
"n9": "transfer"
}
}
83 changes: 47 additions & 36 deletions starknet_py/utils/typed_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
from starknet_py.net.client_utils import _to_rpc_felt
from starknet_py.net.models.typed_data import DomainDict, Revision, TypedDataDict
from starknet_py.net.schemas.common import RevisionField
from starknet_py.serialization.data_serializers import ByteArraySerializer
from starknet_py.utils.merkle_tree import MerkleTree


Expand Down Expand Up @@ -91,40 +92,6 @@ class BasicType(Enum):
TIMESTAMP = "timestamp"


def _encode_value_v1(basic_type: BasicType, value: Union[int, str]) -> Optional[int]:
if basic_type in (
BasicType.FELT,
BasicType.SHORT_STRING,
BasicType.CONTRACT_ADDRESS,
BasicType.CLASS_HASH,
) and isinstance(value, (int, str)):
return parse_felt(value)

if basic_type in (
BasicType.U128,
BasicType.TIMESTAMP,
) and isinstance(value, (int, str)):
return encode_u128(value)

if basic_type == BasicType.I128 and isinstance(value, (int, str)):
return encode_i128(value)

return None


def _encode_value_v0(
basic_type: BasicType,
value: Union[int, str],
) -> Optional[int]:
if basic_type in (
BasicType.FELT,
BasicType.STRING,
) and isinstance(value, (int, str)):
return parse_felt(value)

return None


@dataclass(frozen=True)
class TypedData:
"""
Expand Down Expand Up @@ -167,6 +134,45 @@ def to_dict(self) -> dict:
def _is_struct(self, type_name: str) -> bool:
return type_name in self.types

def _encode_value_v1(
self, basic_type: BasicType, value: Union[int, str, dict, list]
) -> Optional[int]:
if basic_type in (
BasicType.FELT,
BasicType.SHORT_STRING,
BasicType.CONTRACT_ADDRESS,
BasicType.CLASS_HASH,
) and isinstance(value, (int, str)):
return parse_felt(value)

if basic_type in (
BasicType.U128,
BasicType.TIMESTAMP,
) and isinstance(value, (int, str)):
return encode_u128(value)

if basic_type == BasicType.I128 and isinstance(value, (int, str)):
return encode_i128(value)

if basic_type == BasicType.STRING and isinstance(value, str):
return self._encode_long_string(value)

return None

# pylint: disable=no-self-use
def _encode_value_v0(
self,
basic_type: BasicType,
value: Union[int, str, dict, list],
) -> Optional[int]:
if basic_type in (
BasicType.FELT,
BasicType.STRING,
) and isinstance(value, (int, str)):
return parse_felt(value)

return None

def _encode_value(
self,
type_name: str,
Expand All @@ -190,11 +196,11 @@ def _encode_value(
if self.domain.resolved_revision == Revision.V0 and isinstance(
value, (str, int)
):
encoded_value = _encode_value_v0(basic_type, value)
encoded_value = self._encode_value_v0(basic_type, value)
elif self.domain.resolved_revision == Revision.V1 and isinstance(
value, (str, int)
):
encoded_value = _encode_value_v1(basic_type, value)
encoded_value = self._encode_value_v1(basic_type, value)

if encoded_value is not None:
return encoded_value
Expand Down Expand Up @@ -353,6 +359,11 @@ def _get_merkle_tree_leaves_type(self, context: TypeContext) -> str:

return target_type.contains

def _encode_long_string(self, value: str) -> int:
byte_array_serializer = ByteArraySerializer()
serialized_values = byte_array_serializer.serialize(value)
return self._hash_method.hash_many(serialized_values)


def parse_felt(value: Union[int, str]) -> int:
if isinstance(value, int):
Expand Down
7 changes: 7 additions & 0 deletions starknet_py/utils/typed_data_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ class CasesRev0(Enum):
class CasesRev1(Enum):
TD = "typed_data_rev_1_example.json"
TD_FELT_MERKLE_TREE = "typed_data_rev_1_felt_merkletree_example.json"
TD_BASIC_TYPES = "typed_data_rev_1_basic_types_example.json"


def load_typed_data(file_name: str) -> TypedData:
Expand Down Expand Up @@ -68,6 +69,8 @@ def test_parse_felt(value, result):
"Mail(from:Person,to:Person,posts_len:felt,posts:Post*)Person(name:felt,wallet:felt)Post(title:felt,content:felt)"),
(CasesRev1.TD.value, "Mail",
""""Mail"("from":"Person","to":"Person","contents":"felt")"Person"("name":"felt","wallet":"felt")"""),
(CasesRev1.TD_BASIC_TYPES.value, "Example",
""""Example"("n0":"felt","n1":"bool","n2":"string","n3":"selector","n4":"u128","n5":"i128","n6":"ContractAddress","n7":"ClassHash","n8":"timestamp","n9":"shortstring")"""),
(CasesRev1.TD_FELT_MERKLE_TREE.value, "Example", """"Example"("value":"felt","root":"merkletree")""")
],
)
Expand Down Expand Up @@ -96,6 +99,8 @@ def test_encode_type(example, type_name, encoded_type):
(CasesRev1.TD.value, "StarknetDomain", "0x1ff2f602e42168014d405a94f75e8a93d640751d71d16311266e140d8b0a210"),
(CasesRev1.TD.value, "Person", "0x30f7aa21b8d67cb04c30f962dd29b95ab320cb929c07d1605f5ace304dadf34"),
(CasesRev1.TD.value, "Mail", "0x560430bf7a02939edd1a5c104e7b7a55bbab9f35928b1cf5c7c97de3a907bd"),
(
CasesRev1.TD_BASIC_TYPES.value, "Example", "0x1f94cd0be8b4097a41486170fdf09a4cd23aefbc74bb2344718562994c2c111"),
(CasesRev1.TD_FELT_MERKLE_TREE.value, "Example",
"0x160b9c0e8a7c561f9c5d9e3cc2990a1b4d26e94aa319e9eb53e163cd06c71be"),
],
Expand Down Expand Up @@ -150,6 +155,8 @@ def test_struct_hash(example, type_name, attr_name, struct_hash):
"0x5d28fa1b31f92e63022f7d85271606e52bed89c046c925f16b09e644dc99794"),
(CasesRev1.TD.value, "0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826",
"0x7f6e8c3d8965b5535f5cc68f837c04e3bbe568535b71aa6c621ddfb188932b8"),
(CasesRev1.TD_BASIC_TYPES.value, "0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826",
"0x2d80b87b8bc32068247c779b2ef0f15f65c9c449325e44a9df480fb01eb43ec"),
(CasesRev1.TD_FELT_MERKLE_TREE.value, "0xcd2a3d9f938e13cd947ec05abc7fe734df8dd826",
"0x4f706783e0d7d0e61433d41343a248a213e9ab341d50ba978dfc055f26484c9")
],
Expand Down
Loading