diff --git a/src/erc7730/lint/lint.py b/src/erc7730/lint/lint.py index 9224613..bd927bf 100644 --- a/src/erc7730/lint/lint.py +++ b/src/erc7730/lint/lint.py @@ -51,9 +51,8 @@ def lint_all(paths: list[Path], out: OutputAdder) -> int: :param out: output adder :return: number of files checked """ - linter = MultiLinter( - [ValidateABILinter(), ValidateDisplayFieldsLinter(), ClassifyTransactionTypeLinter(), DefinitionLinter()] - ) + input_linter = DefinitionLinter() + output_linter = MultiLinter([ValidateABILinter(), ValidateDisplayFieldsLinter(), ClassifyTransactionTypeLinter()]) files = list(get_erc7730_files(*paths, out=out)) @@ -67,7 +66,11 @@ def label(f: Path) -> Path | None: print(f"🔍 checking {len(files)} descriptor files…\n") with ThreadPoolExecutor() as executor: - for future in (executor.submit(lint_file, file, linter, out, label(file)) for file in files): + for future in (executor.submit(lint_file, file, input_linter, out, label(file)) for file in files): + future.result() + + with ThreadPoolExecutor() as executor: + for future in (executor.submit(lint_file, file, output_linter, out, label(file)) for file in files): future.result() return len(files) diff --git a/src/erc7730/lint/lint_validate_definitions.py b/src/erc7730/lint/lint_validate_definitions.py index ceaa013..85c7c80 100644 --- a/src/erc7730/lint/lint_validate_definitions.py +++ b/src/erc7730/lint/lint_validate_definitions.py @@ -14,15 +14,18 @@ class DefinitionLinter(ERC7730Linter): @override def lint(self, descriptor: ResolvedERC7730Descriptor | InputERC7730Descriptor, out: OutputAdder) -> None: if isinstance(descriptor, InputERC7730Descriptor) and descriptor.display.definitions is not None: - for _, definition in descriptor.display.definitions.items(): + for name, _ in descriptor.display.definitions.items(): found = False for _, format in descriptor.display.formats.items(): if found is False: for field in format.fields: - if isinstance(field, InputReference) and field.ref == definition.label: + if ( + isinstance(field, InputReference) + and field.ref.__str__() == f"$.display.definitions.{name}" + ): found = True if found is False: out.error( title="Unused field definition", - message=f"Field {definition.label} is not used in descriptor formats.", + message=f"Field {name} is not used in descriptor formats.", ) diff --git a/tests/lint/resources/calldata-unused-definitions.json b/tests/lint/resources/calldata-unused-definitions.json new file mode 100644 index 0000000..2371d46 --- /dev/null +++ b/tests/lint/resources/calldata-unused-definitions.json @@ -0,0 +1,71 @@ +{ + "context": { + "$id": "AugustusSwapper", + "contract" : { + "abi": "https://github.com/LedgerHQ/ledger-asset-dapps/blob/main/ethereum/paraswap/abis/0x1bd435f3c054b6e901b7b108a0ab7617c808677b.abi.json", + "deployments": [ + { + "chainId": 1, + "address": "0x1bd435f3c054b6e901b7b108a0ab7617c808677b" + }, + { + "chainId": 1, + "address": "0xdef171fe48cf0115b1d80b88dc8eab59176fee57" + }, + { + "chainId": 56, + "address": "0x55a0e3b6579972055faa983482aceb4b251dcf15" + }, + { + "chainId": 56, + "address": "0xdef171fe48cf0115b1d80b88dc8eab59176fee57" + }, + { + "chainId": 137, + "address": "0x90249ed4d69d70e709ffcd8bee2c5a566f65dade" + }, + { + "chainId": 137, + "address": "0xdef171fe48cf0115b1d80b88dc8eab59176fee57" + } + ] + } + }, + + "metadata": { + "owner": "Paraswap" + }, + + "display": { + "definitions": { + "amountIn": { + "label": "Income Amount", + "format": "amount" + }, + "amountOut": { + "label": "Outcome Amount", + "format": "amount" + }, + "amountOutIn": { + "label": "Outcome/Income Amount", + "format": "amount" + } + }, + "formats": { + "0xcfc0afeb" : { + "$id": "swapOnZeroXv2", + "fields": [ + { + "path": "amountIn", + "$ref": "$.display.definitions.amountIn" + }, + { + "path": "amountOut", + "$ref": "$.display.definitions.amountOut" + } + ], + "required": ["amountIn", "amountOut"] + } + } + } +} diff --git a/tests/lint/test_lint.py b/tests/lint/test_lint.py index db198b2..cb530f3 100644 --- a/tests/lint/test_lint.py +++ b/tests/lint/test_lint.py @@ -2,10 +2,13 @@ import pytest -from erc7730.lint.lint import lint_all_and_print_errors +from erc7730.common.output import SetOutputAdder +from erc7730.lint.lint import lint_all, lint_all_and_print_errors from tests.cases import path_id from tests.files import ERC7730_DESCRIPTORS +RESOURCES = Path(__file__).resolve().parent / "resources" + @pytest.mark.parametrize("input_file", ERC7730_DESCRIPTORS, ids=path_id) def test_registry_files(input_file: Path) -> None: @@ -18,3 +21,18 @@ def test_registry_files(input_file: Path) -> None: pytest.skip("Descriptor uses literal constants instead of token paths, which is not supported yet") assert lint_all_and_print_errors([input_file]) + + +def test_unused_definition_detected_by_linter() -> None: + """ + Test unused field definition is detected within an ERC-7730 file + """ + output_adder = SetOutputAdder() + + input_file = RESOURCES / "calldata-unused-definitions.json" + + lint_all([input_file], output_adder) + + assert output_adder.has_errors is True + + assert "Unused field definition" in (set(map(lambda x: x.title, output_adder.outputs)))