diff --git a/demo-registry/uniswap/eip712-permit2.json b/demo-registry/uniswap/eip712-permit2.json index 9dcdfbd..bff40f2 100644 --- a/demo-registry/uniswap/eip712-permit2.json +++ b/demo-registry/uniswap/eip712-permit2.json @@ -140,13 +140,6 @@ "params": { "tokenPath": "details.token" } - }, - "details.expiration": { - "label": "Valid Until", - "format": "date", - "params": { - "encoding": "timestamp" - } } }, "required": [ diff --git a/src/erc7730/classifier/eip712_classifier.py b/src/erc7730/classifier/eip712_classifier.py index 5a65e1b..f1d63d0 100644 --- a/src/erc7730/classifier/eip712_classifier.py +++ b/src/erc7730/classifier/eip712_classifier.py @@ -8,4 +8,6 @@ class EIP712Classifier(Classifier[EIP712JsonSchema]): @override def classify(self, schema: EIP712JsonSchema) -> TxClass | None: - pass + if "permit" in schema.primaryType.lower(): + return TxClass.PERMIT + return None diff --git a/src/erc7730/display_format_checker/__init__.py b/src/erc7730/display_format_checker/__init__.py index ba3cb5f..7d5ea46 100644 --- a/src/erc7730/display_format_checker/__init__.py +++ b/src/erc7730/display_format_checker/__init__.py @@ -1,6 +1,16 @@ from erc7730.classifier import TxClass from erc7730.linter import Linter -from erc7730.model.display import Display +from erc7730.model.display import Display, Format + + +def _fields_contain(word: str, fields: set[str]) -> bool: + """ + to check if the provided keyword is contained in one of the fields (case insensitive) + """ + for field in fields: + if word.lower() in field.lower(): + return True + return False class DisplayFormatChecker: @@ -8,5 +18,42 @@ def __init__(self, c: TxClass, d: Display): self.c = c self.d = d + def _get_all_displayed_fields(self, formats: dict[str, Format]) -> set[str]: + fields: set[str] = set() + for format in formats.values(): + if format.fields is not None: + for field in format.fields.root.keys(): + fields.add(str(field)) + return fields + def check(self) -> list[Linter.Output]: - return [] + res: list[Linter.Output] = [] + match self.c: + case TxClass.PERMIT: + formats = self.d.formats + fields = self._get_all_displayed_fields(formats) + if not _fields_contain("spender", fields): + res.append( + Linter.Output( + title="Missing spender in displayed fields", message="", level=Linter.Output.Level.ERROR + ) + ) + if not _fields_contain("amount", fields): + res.append( + Linter.Output( + title="Missing amount in displayed fields", message="", level=Linter.Output.Level.ERROR + ) + ) + if ( + not _fields_contain("valid until", fields) + and not _fields_contain("expiry", fields) + and not _fields_contain("expiration", fields) + ): + res.append( + Linter.Output( + title="Missing expiration date in displayed fields for permit", + message="", + level=Linter.Output.Level.ERROR, + ) + ) + return res diff --git a/src/erc7730/linter/linter_transaction_type_classifier_ai.py b/src/erc7730/linter/linter_transaction_type_classifier_ai.py index 796d176..4b209b8 100644 --- a/src/erc7730/linter/linter_transaction_type_classifier_ai.py +++ b/src/erc7730/linter/linter_transaction_type_classifier_ai.py @@ -40,7 +40,15 @@ def lint(self, descriptor: ERC7730Descriptor, out: Linter.OutputAdder) -> None: return None c = determine_tx_class(descriptor) if c is None: + out( + Linter.Output( + title="Transaction type: ", + message="could not determine transaction type", + level=Linter.Output.Level.WARNING, + ) + ) return None + out(Linter.Output(title="Transaction type: ", message=str(c), level=Linter.Output.Level.INFO)) d: Display | None = descriptor.display if d is None: return None diff --git a/src/erc7730/model/display.py b/src/erc7730/model/display.py index eedd64a..aaabb32 100644 --- a/src/erc7730/model/display.py +++ b/src/erc7730/model/display.py @@ -74,7 +74,7 @@ class StructFormats(BaseLibraryModel): fields: ForwardRef("Fields") # type: ignore -class Fields(RootModel[dict[str, Union[Reference, Field, StructFormats]]]): +class Fields(RootModel[dict[str, Union[Reference, FieldDescription, Field, StructFormats]]]): """todo use StructFormats instead"""