diff --git a/src/erc7730/mapper/mapper.py b/src/erc7730/mapper/mapper.py index bd19595..5b959ac 100644 --- a/src/erc7730/mapper/mapper.py +++ b/src/erc7730/mapper/mapper.py @@ -1,12 +1,14 @@ from pydantic import AnyUrl from erc7730.common.pydantic import model_from_json_bytes -from erc7730.model.context import EIP712JsonSchema +from erc7730.model.context import EIP712JsonSchema, EIP712Context, EIP712, Domain, EIP712Domain from erc7730.model.erc7730_descriptor import ERC7730Descriptor, EIP712Context -from erc7730.model.display import Display, Reference, Field, StructFormats, FieldFormat, Fields +from erc7730.model.display import Display, Reference, Field, StructFormats, FieldFormat, Fields, Format, DateParameters, DateEncoding, TokenAmountParameters from eip712 import EIP712DAppDescriptor, EIP712ContractDescriptor, EIP712Mapper, EIP712MessageDescriptor, EIP712Field, EIP712Format import requests +from erc7730.model.metadata import Metadata + def to_eip712_mapper(erc7730: ERC7730Descriptor) -> EIP712DAppDescriptor|list[Exception]: exceptions = list[Exception]() @@ -92,4 +94,40 @@ def parseField(primaryType: str, output: list[EIP712Field], field: Field) -> lis pass output.append(EIP712Field(path=primaryType, label=name, assetPath=assetPath, format=fieldFormat, coinRef=None)) return output - + +def to_erc7730_mapper(eip712DappDescriptor: EIP712DAppDescriptor) -> ERC7730Descriptor: + verifyingContract = None + if eip712DappDescriptor.contracts.__len__() > 0: + verifyingContract = eip712DappDescriptor.contracts[0].address + domain = Domain(name = eip712DappDescriptor.name, version = None, chainId = eip712DappDescriptor.chain_id, verifyingContract = verifyingContract) + formats = dict[str,Format]() + schemas = list[EIP712JsonSchema | AnyUrl]() + for contract in eip712DappDescriptor.contracts: + types = dict[str, list[EIP712Domain]]() + for message in contract.messages: + mapper = message.mapper + fields = dict[str, Reference | Field | StructFormats]() + eip712Domains = list[EIP712Domain]() + for item in mapper.fields: + dateParameters = None + tokenAmountParameters = None + if item.format is not None: + match item.format: + case EIP712Format.AMOUNT: + if item.assetPath is not None: + tokenAmountParameters = TokenAmountParameters(tokenPath=item.assetPath) + case EIP712Format.DATETIME: + dateParameters = DateParameters(encoding=DateEncoding.TIMESTAMP) + case _: + pass + fields[item.label] = Field(sources=None, collectionPath=None, tokenAmountParameters=tokenAmountParameters, allowanceAmountParameters=None, percentageParameters=None, dateParameters=dateParameters, enumParameters=None) + eip712Domains.append(EIP712Domain(name = item.label, type = item.format.name)) + types[mapper.label] = eip712Domains + formats[mapper.label] = Format(id=None, intent=None, fields=Fields(root=fields), required=None, screens=None) + schemas.append(EIP712JsonSchema(primaryType = mapper.label, types = types)) + + eip712 = EIP712(domain = domain, schemas = schemas) + context = EIP712Context(eip712 = eip712) + display = Display(definitions=None, formats = formats) + metadata = Metadata(owner=None, info=None, token=None, constants=None, enums=None) + return ERC7730Descriptor(context = context, includes=None, metadata=metadata, display=display) diff --git a/src/erc7730/model/display.py b/src/erc7730/model/display.py index 3f6c181..43799c2 100644 --- a/src/erc7730/model/display.py +++ b/src/erc7730/model/display.py @@ -1,6 +1,6 @@ from erc7730.model.base import BaseLibraryModel from erc7730.model.types import Id -from typing import ForwardRef, Optional, Dict, Union +from typing import ForwardRef, Optional, Union from enum import StrEnum from pydantic import RootModel, Field as PydanticField @@ -24,7 +24,7 @@ class FieldFormat(StrEnum): class Reference(BaseLibraryModel): ref: str = PydanticField(alias='$ref') - params: Optional[Dict[str, str]] + params: Optional[dict[str, str]] class TokenAmountParameters(BaseLibraryModel): tokenPath: str @@ -63,7 +63,7 @@ class FieldDescription(BaseLibraryModel): class StructFormats(BaseLibraryModel): fields: ForwardRef('Fields') # type: ignore -class Fields(RootModel[Dict[str, Union[Reference, Field, StructFormats]]]): +class Fields(RootModel[dict[str, Union[Reference, Field, StructFormats]]]): """ todo use StructFormats instead """ StructFormats.model_rebuild() @@ -75,10 +75,10 @@ class Format(BaseLibraryModel): intent: Optional[str] = None fields: Optional[Fields] = None required: Optional[list[str]] = None - screens: Optional[Dict[str, list[Screen]]] = None + screens: Optional[dict[str, list[Screen]]] = None class Display(BaseLibraryModel): - definitions: Optional[Dict[str, Field]] = None - formats: Dict[str, Format] + definitions: Optional[dict[str, Field]] = None + formats: dict[str, Format] diff --git a/tests/src/erc7730/test_mapper.py b/tests/src/erc7730/test_mapper.py index e6c90c4..471da91 100644 --- a/tests/src/erc7730/test_mapper.py +++ b/tests/src/erc7730/test_mapper.py @@ -1,15 +1,28 @@ from pathlib import Path from erc7730.common.pydantic import model_from_json_file_or_none from erc7730.model.erc7730_descriptor import ERC7730Descriptor -from erc7730.mapper.mapper import to_eip712_mapper +from erc7730.mapper.mapper import to_eip712_mapper, to_erc7730_mapper +import pytest +import glob +files = glob.glob('clear-signing-erc7730-registry/registry/*/eip712*.json') + +@pytest.mark.parametrize("file", files) +def roundtrip(file: str) -> None: + erc7730Descriptor = model_from_json_file_or_none(Path(file), ERC7730Descriptor) + assert erc7730Descriptor is not None + eip712DappDescriptor = to_eip712_mapper(erc7730Descriptor) + assert eip712DappDescriptor is not None + newErc7730Descriptor = to_erc7730_mapper(eip712DappDescriptor) + assert newErc7730Descriptor is not None + assert newErc7730Descriptor == erc7730Descriptor def test_to_eip712_mapper() -> None: uniswap_eip712_cs_descriptor = model_from_json_file_or_none(Path("clear-signing-erc7730-registry/registry/uniswap/eip712-permit2.json"), ERC7730Descriptor) assert uniswap_eip712_cs_descriptor is not None - eip712_mapper = to_eip712_mapper(uniswap_eip712_cs_descriptor) - assert eip712_mapper is not None - assert eip712_mapper.chain_id == 1 - assert eip712_mapper.name == "Permit2" - assert eip712_mapper.contracts.__len__() == 2 - assert eip712_mapper.contracts[0].messages.__len__() == 1 + eip712DappDescriptor = to_eip712_mapper(uniswap_eip712_cs_descriptor) + assert eip712DappDescriptor is not None + assert eip712DappDescriptor.chain_id == 1 + assert eip712DappDescriptor.name == "Permit2" + assert eip712DappDescriptor.contracts.__len__() == 2 + assert eip712DappDescriptor.contracts[0].messages.__len__() == 1