From f8a63bc74635a9b0d0e41e7309cdbb626cbed9fb Mon Sep 17 00:00:00 2001 From: cguerre-giordano Date: Tue, 17 Sep 2024 16:09:46 +0200 Subject: [PATCH] Rountrip test --- .pre-commit-config.yaml | 131 +++++++++++++++++++++++++++++++ src/erc7730/mapper/mapper.py | 46 ++++++++++- src/erc7730/model/display.py | 14 ++-- tests/src/erc7730/test_mapper.py | 27 +++++-- 4 files changed, 200 insertions(+), 18 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index e69de29..af67c0a 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -0,0 +1,131 @@ +# TODO enable these +repos: + + - repo: https://github.com/mxr/sync-pre-commit-deps + rev: v0.0.1 + hooks: + - id: sync-pre-commit-deps + name: sync pre-commit dependencies + +# - repo: https://github.com/astral-sh/ruff-pre-commit +# rev: v0.6.4 +# hooks: +# - id: ruff +# name: lint code (ruff) +# args: +# - --fix +# - id: ruff-format +# name: format code (ruff) +# +# - repo: https://github.com/pre-commit/mirrors-mypy +# rev: v1.10.0 +# hooks: +# - id: mypy +# name: lint code typing (mypy) +# additional_dependencies: +# - pandas-stubs +# - types-docutils +# - types-PyYAML +# - types-requests +# - types-setuptools +# - types-protobuf +# - pydantic +# - pytest +# + - repo: https://github.com/pdm-project/pdm + rev: 2.18.1 + hooks: + - id: pdm-lock-check + name: check pdm lock file + + - repo: https://github.com/adrienverge/yamllint.git + rev: v1.29.0 + hooks: + - id: yamllint + name: check yaml files (yamllint) + + - repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.5.0 + hooks: + - id: check-ast + - id: check-builtin-literals + - id: check-case-conflict + - id: check-docstring-first + - id: check-executables-have-shebangs + - id: check-merge-conflict + - id: check-shebang-scripts-are-executable + - id: check-symlinks + - id: check-toml + - id: check-json + - id: check-yaml + - id: check-vcs-permalinks + - id: debug-statements + - id: destroyed-symlinks + - id: detect-private-key + - id: end-of-file-fixer + - id: forbid-new-submodules + - id: mixed-line-ending + - id: fix-byte-order-marker + # - id: no-commit-to-branch TODO (temporary for development) + +# - repo: https://github.com/asottile/pyupgrade +# rev: v3.15.2 +# hooks: +# - id: pyupgrade +# name: upgrade to python 3.12 syntax (pyupgrade) +# args: +# - --py310-plus +# +# - repo: https://github.com/hadialqattan/pycln +# rev: v2.4.0 +# hooks: +# - id: pycln +# name: remove unused imports (pycln) +# args: +# - --all +# - --disable-all-dunder-policy +# +# - repo: https://github.com/MarcoGorelli/absolufy-imports +# rev: v0.3.1 +# hooks: +# - id: absolufy-imports +# name: make imports absolute +# +# - repo: https://github.com/pycqa/isort +# rev: 5.13.2 +# hooks: +# - id: isort +# name: sort imports (isort) +# language_version: python3 +# args: +# - --profile=black +# +# - repo: https://github.com/MarcoGorelli/auto-walrus +# rev: 0.3.4 +# hooks: +# - id: auto-walrus +# name: apply walrus operator +# +# - repo: https://github.com/PyCQA/bandit +# rev: 1.7.8 +# hooks: +# - id: bandit +# name: lint code security issues (bandit) +# args: ["-c", "pyproject.toml"] +# additional_dependencies: +# - bandit[toml] +# +# - repo: https://github.com/codespell-project/codespell +# rev: v2.2.6 +# hooks: +# - id: codespell +# name: lint docs spelling (codespell) +# additional_dependencies: +# - tomli + +# FIXME false positive: unknown permission scope "attestations". +# - repo: https://github.com/rhysd/actionlint +# rev: v1.6.27 +# hooks: +# - id: actionlint +# name: lint Github Actions workflows (actionlint) diff --git a/src/erc7730/mapper/mapper.py b/src/erc7730/mapper/mapper.py index 1149664..33bde33 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,42 @@ 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 - \ No newline at end of file + + +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 d5a1a6d..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,12 +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