diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index c196d365e..9038306d6 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -44,7 +44,7 @@ jobs: path: dist/ - name: publish - uses: pypa/gh-action-pypi-publish@v1.12.3 + uses: pypa/gh-action-pypi-publish@v1.12.4 - name: sign uses: sigstore/gh-action-sigstore-python@v3.0.0 diff --git a/README.md b/README.md index ebbc6faab..c75c76a2f 100644 --- a/README.md +++ b/README.md @@ -82,6 +82,12 @@ python3 -m pip install slither-analyzer python3 -m pip install --upgrade slither-analyzer ``` +### Using Brew + +```console +brew install slither-analyzer +``` + ### Using Git ```bash @@ -159,7 +165,7 @@ Num | Detector | What it Detects | Impact | Confidence 35 | `locked-ether` | [Contracts that lock ether](https://github.com/crytic/slither/wiki/Detector-Documentation#contracts-that-lock-ether) | Medium | High 36 | `mapping-deletion` | [Deletion on mapping containing a structure](https://github.com/crytic/slither/wiki/Detector-Documentation#deletion-on-mapping-containing-a-structure) | Medium | High 37 | `pyth-deprecated-functions` | [Detect Pyth deprecated functions](https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-deprecated-functions) | Medium | High -38 | `pyth-unchecked-confidence` | [Detect when the confidence level of a Pyth price is not checked](https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-unchecked-confidence) | Medium | High +38 | `pyth-unchecked-confidence` | [Detect when the confidence level of a Pyth price is not checked](https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-unchecked-confidence-level) | Medium | High 39 | `pyth-unchecked-publishtime` | [Detect when the publishTime of a Pyth price is not checked](https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-unchecked-publishtime) | Medium | High 40 | `shadowing-abstract` | [State variables shadowing from abstract contracts](https://github.com/crytic/slither/wiki/Detector-Documentation#state-variable-shadowing-from-abstract-contracts) | Medium | High 41 | `tautological-compare` | [Comparing a variable to itself always returns true or false, depending on comparison](https://github.com/crytic/slither/wiki/Detector-Documentation#tautological-compare) | Medium | High @@ -179,9 +185,9 @@ Num | Detector | What it Detects | Impact | Confidence 55 | `unchecked-send` | [Unchecked send](https://github.com/crytic/slither/wiki/Detector-Documentation#unchecked-send) | Medium | Medium 56 | `uninitialized-local` | [Uninitialized local variables](https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-local-variables) | Medium | Medium 57 | `unused-return` | [Unused return values](https://github.com/crytic/slither/wiki/Detector-Documentation#unused-return) | Medium | Medium -58 | `chainlink-feed-registry` | [Detect when chainlink feed registry is used](https://github.com/crytic/slither/wiki/Detector-Documentation#chainlink-feed-registry) | Low | High +58 | `chainlink-feed-registry` | [Detect when chainlink feed registry is used](https://github.com/crytic/slither/wiki/Detector-Documentation#chainlink-feed-registry-usage) | Low | High 59 | `incorrect-modifier` | [Modifiers that can return the default value](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-modifier) | Low | High -60 | `optimism-deprecation` | [Detect when deprecated Optimism predeploy or function is used.](https://github.com/crytic/slither/wiki/Detector-Documentation#optimism-deprecation) | Low | High +60 | `optimism-deprecation` | [Detect when deprecated Optimism predeploy or function is used.](https://github.com/crytic/slither/wiki/Detector-Documentation#optimism-deprecated-predeploy-or-function) | Low | High 61 | `shadowing-builtin` | [Built-in symbol shadowing](https://github.com/crytic/slither/wiki/Detector-Documentation#builtin-symbol-shadowing) | Low | High 62 | `shadowing-local` | [Local variables shadowing](https://github.com/crytic/slither/wiki/Detector-Documentation#local-variable-shadowing) | Low | High 63 | `uninitialized-fptr-cst` | [Uninitialized function pointer calls in constructors](https://github.com/crytic/slither/wiki/Detector-Documentation#uninitialized-function-pointers-in-constructors) | Low | High @@ -203,7 +209,7 @@ Num | Detector | What it Detects | Impact | Confidence 79 | `deprecated-standards` | [Deprecated Solidity Standards](https://github.com/crytic/slither/wiki/Detector-Documentation#deprecated-standards) | Informational | High 80 | `erc20-indexed` | [Un-indexed ERC20 event parameters](https://github.com/crytic/slither/wiki/Detector-Documentation#unindexed-erc20-event-parameters) | Informational | High 81 | `function-init-state` | [Function initializing state variables](https://github.com/crytic/slither/wiki/Detector-Documentation#function-initializing-state) | Informational | High -82 | `incorrect-using-for` | [Detects using-for statement usage when no function from a given library matches a given type](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-using-for-usage) | Informational | High +82 | `incorrect-using-for` | [Detects using-for statement usage when no function from a given library matches a given type](https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-usage-of-using-for-statement) | Informational | High 83 | `low-level-calls` | [Low level calls](https://github.com/crytic/slither/wiki/Detector-Documentation#low-level-calls) | Informational | High 84 | `missing-inheritance` | [Missing inheritance](https://github.com/crytic/slither/wiki/Detector-Documentation#missing-inheritance) | Informational | High 85 | `naming-convention` | [Conformity to Solidity naming conventions](https://github.com/crytic/slither/wiki/Detector-Documentation#conformance-to-solidity-naming-conventions) | Informational | High @@ -232,10 +238,11 @@ For more information, see ### Quick Review Printers -* `human-summary`: [Print a human-readable summary of the contracts](https://github.com/crytic/slither/wiki/Printer-documentation#human-summary) -* `inheritance-graph`: [Export the inheritance graph of each contract to a dot file](https://github.com/crytic/slither/wiki/Printer-documentation#inheritance-graph) -* `contract-summary`: [Print a summary of the contracts](https://github.com/crytic/slither/wiki/Printer-documentation#contract-summary) -* `loc`: [Count the total number lines of code (LOC), source lines of code (SLOC), and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP), and test files (TEST).](https://github.com/crytic/slither/wiki/Printer-documentation#loc) +* `human-summary`: [Print a human-readable summary of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#human-summary) +* `inheritance-graph`: [Export the inheritance graph of each contract to a dot file](https://github.com/trailofbits/slither/wiki/Printer-documentation#inheritance-graph) +* `contract-summary`: [Print a summary of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#contract-summary) +* `loc`: [Count the total number lines of code (LOC), source lines of code (SLOC), and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP), and test files (TEST).](https://github.com/trailofbits/slither/wiki/Printer-documentation#loc) +* `entry-points`: [Print all the state-changing entry point functions of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#entry-points) ### In-Depth Review Printers diff --git a/slither/detectors/functions/chainlink_feed_registry.py b/slither/detectors/functions/chainlink_feed_registry.py index 82ab17424..6367516dc 100644 --- a/slither/detectors/functions/chainlink_feed_registry.py +++ b/slither/detectors/functions/chainlink_feed_registry.py @@ -15,7 +15,7 @@ class ChainlinkFeedRegistry(AbstractDetector): IMPACT = DetectorClassification.LOW CONFIDENCE = DetectorClassification.HIGH - WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#chainlink-feed-registry" + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#chainlink-feed-registry-usage" WIKI_TITLE = "Chainlink Feed Registry usage" WIKI_DESCRIPTION = "Detect when Chainlink Feed Registry is used. At the moment is only available on Ethereum Mainnet." diff --git a/slither/detectors/functions/optimism_deprecation.py b/slither/detectors/functions/optimism_deprecation.py index 752e8bb2d..b4d0a4153 100644 --- a/slither/detectors/functions/optimism_deprecation.py +++ b/slither/detectors/functions/optimism_deprecation.py @@ -18,7 +18,7 @@ class OptimismDeprecation(AbstractDetector): IMPACT = DetectorClassification.LOW CONFIDENCE = DetectorClassification.HIGH - WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#optimism-deprecation" + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#optimism-deprecated-predeploy-or-function" WIKI_TITLE = "Optimism deprecated predeploy or function" WIKI_DESCRIPTION = "Detect when deprecated Optimism predeploy or function is used." diff --git a/slither/detectors/statements/incorrect_using_for.py b/slither/detectors/statements/incorrect_using_for.py index e2e87e7e0..f964082ab 100644 --- a/slither/detectors/statements/incorrect_using_for.py +++ b/slither/detectors/statements/incorrect_using_for.py @@ -165,7 +165,7 @@ class IncorrectUsingFor(AbstractDetector): IMPACT = DetectorClassification.INFORMATIONAL CONFIDENCE = DetectorClassification.HIGH - WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-using-for-usage" + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#incorrect-usage-of-using-for-statement" WIKI_TITLE = "Incorrect usage of using-for statement" WIKI_DESCRIPTION = ( diff --git a/slither/detectors/statements/pyth_unchecked.py b/slither/detectors/statements/pyth_unchecked.py index 959aee6a5..fa3f91b2f 100644 --- a/slither/detectors/statements/pyth_unchecked.py +++ b/slither/detectors/statements/pyth_unchecked.py @@ -24,13 +24,13 @@ def _detect(self) -> List[Output]: for contract in self.compilation_unit.contracts_derived: for target_contract, ir in contract.all_high_level_calls: if target_contract.name == "IPyth" and ir.function_name in self.PYTH_FUNCTIONS: - # We know for sure the second IR in the node is an Assignment operation of the TMP variable. Example: + # We know for sure the last IR in the node is an Assignment operation of the TMP variable. Example: # Expression: price = pyth.getEmaPriceNoOlderThan(id,age) # IRs: # TMP_0(PythStructs.Price) = HIGH_LEVEL_CALL, dest:pyth(IPyth), function:getEmaPriceNoOlderThan, arguments:['id', 'age'] # price(PythStructs.Price) := TMP_0(PythStructs.Price) - assert isinstance(ir.node.irs[1], Assignment) - return_variable = ir.node.irs[1].lvalue + assert isinstance(ir.node.irs[len(ir.node.irs) - 1], Assignment) + return_variable = ir.node.irs[len(ir.node.irs) - 1].lvalue checked = False possible_unchecked_variable_ir = None diff --git a/slither/detectors/statements/pyth_unchecked_confidence.py b/slither/detectors/statements/pyth_unchecked_confidence.py index 2e99851a8..f1cc3d33b 100644 --- a/slither/detectors/statements/pyth_unchecked_confidence.py +++ b/slither/detectors/statements/pyth_unchecked_confidence.py @@ -12,7 +12,7 @@ class PythUncheckedConfidence(PythUnchecked): IMPACT = DetectorClassification.MEDIUM CONFIDENCE = DetectorClassification.HIGH - WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-unchecked-confidence" + WIKI = "https://github.com/crytic/slither/wiki/Detector-Documentation#pyth-unchecked-confidence-level" WIKI_TITLE = "Pyth unchecked confidence level" WIKI_DESCRIPTION = "Detect when the confidence level of a Pyth price is not checked" WIKI_RECOMMENDATION = "Check the confidence level of a Pyth price. Visit https://docs.pyth.network/price-feeds/best-practices#confidence-intervals for more information." diff --git a/slither/printers/all_printers.py b/slither/printers/all_printers.py index 034578f52..d3e836d71 100644 --- a/slither/printers/all_printers.py +++ b/slither/printers/all_printers.py @@ -25,3 +25,4 @@ from .functions.dominator import Dominator from .summary.martin import Martin from .summary.cheatcodes import CheatcodePrinter +from .summary.entry_points import PrinterEntryPoints diff --git a/slither/printers/summary/entry_points.py b/slither/printers/summary/entry_points.py new file mode 100644 index 000000000..ab4d74756 --- /dev/null +++ b/slither/printers/summary/entry_points.py @@ -0,0 +1,94 @@ +""" +Module printing all the state-changing entry point functions of the contracts +""" + +from slither.printers.abstract_printer import AbstractPrinter +from slither.core.declarations.function_contract import FunctionContract +from slither.utils.colors import Colors +from slither.utils.output import Output +from slither.utils.myprettytable import MyPrettyTable + + +class PrinterEntryPoints(AbstractPrinter): + + ARGUMENT = "entry-points" + HELP = "Print all the state-changing entry point functions of the contracts" + + WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#entry-points" + + def output(self, _filename) -> Output: + """ + _filename is not used + Args: + _filename(string) + """ + all_contracts = [] + + for contract in sorted( + ( + c + for c in self.contracts + if not c.is_interface + and not c.is_library + and not c.is_abstract + and "lib/" not in c.source_mapping.filename.absolute + and "node_modules/" not in c.source_mapping.filename.absolute + and not any( + mock in c.source_mapping.filename.absolute.lower() for mock in ["mock", "mocks"] + ) + ), + key=lambda x: x.name, + ): + entry_points = [ + f + for f in contract.functions + if ( + f.visibility in ["public", "external"] + and isinstance(f, FunctionContract) + and not f.is_constructor + and not f.view + and not f.pure + and not f.contract_declarer.is_interface + and not f.contract_declarer.is_library + and not f.is_shadowed + ) + ] + + if not entry_points: + continue + + table = MyPrettyTable(["Function", "Modifiers", "Inherited From"]) + contract_info = [ + f"\nContract {Colors.BOLD}{Colors.YELLOW}{contract.name}{Colors.END}" + f" ({contract.source_mapping})" + ] + + for f in sorted( + entry_points, + key=lambda x: (x.visibility != "external", x.visibility != "public", x.full_name), + ): + modifier_list = [m.name for m in f.modifiers] + if f.payable: + modifier_list.append("payable") + modifiers = ", ".join(modifier_list) if modifier_list else "" + inherited = f"{f.contract_declarer.name}" if f.contract_declarer != contract else "" + + name_parts = f.full_name.split("(", 1) + function_name = ( + f"{Colors.BOLD}{Colors.RED}{name_parts[0]}{Colors.END}" f"({name_parts[1]}" + ) + + table.add_row( + [ + function_name, + f"{Colors.GREEN}{modifiers}{Colors.END}" if modifiers else "", + f"{Colors.MAGENTA}{inherited}{Colors.END}" if inherited else "", + ] + ) + + contract_info.append(str(table)) + all_contracts.append("\n".join(contract_info)) + + info = "\n".join(all_contracts) if all_contracts else "" + self.info(info) + return self.generate_output(info) diff --git a/slither/tools/documentation/README.md b/slither/tools/documentation/README.md index 218f2e91d..367d46d1d 100644 --- a/slither/tools/documentation/README.md +++ b/slither/tools/documentation/README.md @@ -1,5 +1,5 @@ # slither-documentation -`slither-documentation` uses [codex](https://platform.openai.com) to generate natspec documenation. +`slither-documentation` uses [codex](https://platform.openai.com) to generate natspec documentation. This tool is experimental. See [solmate documentation](https://github.com/montyly/solmate/pull/1) for an example of usage. diff --git a/slither/tools/mutator/README.md b/slither/tools/mutator/README.md index aa4d86655..b33c5f4fb 100644 --- a/slither/tools/mutator/README.md +++ b/slither/tools/mutator/README.md @@ -33,8 +33,7 @@ options: --timeout TIMEOUT Set timeout for test command (by default 30 seconds) --output-dir OUTPUT_DIR Name of output directory (by default 'mutation_campaign') - -v, --verbose log mutants that are caught as well as those that are uncaught - -vv, --very-verbose log mutants that are caught, uncaught, and fail to compile. And more! + -v, --verbose log mutants that are caught, uncaught, and fail to compile --mutators-to-run MUTATORS_TO_RUN mutant generators to run --contract-names CONTRACT_NAMES diff --git a/slither/tools/mutator/__main__.py b/slither/tools/mutator/__main__.py index f71ef26b5..7d97d79be 100644 --- a/slither/tools/mutator/__main__.py +++ b/slither/tools/mutator/__main__.py @@ -72,7 +72,7 @@ def parse_args() -> argparse.Namespace: parser.add_argument( "-v", "--verbose", - help="log mutants that are caught as well as those that are uncaught", + help="log mutants that are caught, uncaught, and fail to compile", action="store_true", default=False, ) diff --git a/slither/tools/mutator/mutators/AOR.py b/slither/tools/mutator/mutators/AOR.py index 1e9008efe..a0af48abb 100644 --- a/slither/tools/mutator/mutators/AOR.py +++ b/slither/tools/mutator/mutators/AOR.py @@ -2,12 +2,9 @@ from slither.slithir.operations import Binary, BinaryType from slither.tools.mutator.utils.patch import create_patch_with_line from slither.tools.mutator.mutators.abstract_mutator import AbstractMutator -from slither.core.variables.variable import Variable from slither.core.expressions.unary_operation import UnaryOperation from slither.core.expressions.call_expression import CallExpression from slither.core.expressions.member_access import MemberAccess -from slither.core.expressions.identifier import Identifier -from slither.core.solidity_types.array_type import ArrayType arithmetic_operators = [ BinaryType.ADDITION, @@ -42,9 +39,6 @@ def _mutate(self) -> Dict: isinstance(ir_expression, CallExpression) and isinstance(ir_expression.called, MemberAccess) and ir_expression.called.member_name == "pop" - and isinstance(ir_expression.called.expression, Identifier) - and isinstance(ir_expression.called.expression.value, Variable) - and isinstance(ir_expression.called.expression.value.type, ArrayType) ): continue @@ -58,9 +52,6 @@ def _mutate(self) -> Dict: if isinstance(ir_expression, CallExpression) and isinstance(ir_expression.called, MemberAccess) and ir_expression.called.member_name == "push" - and isinstance(ir_expression.called.expression, Identifier) - and isinstance(ir_expression.called.expression.value, Variable) - and isinstance(ir_expression.called.expression.value.type, ArrayType) else node.irs ) diff --git a/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedConfidence_0_8_20_pyth_unchecked_confidence_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedConfidence_0_8_20_pyth_unchecked_confidence_sol__0.txt index ae0dc2ae2..737b053fd 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedConfidence_0_8_20_pyth_unchecked_confidence_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedConfidence_0_8_20_pyth_unchecked_confidence_sol__0.txt @@ -1,3 +1,6 @@ -Pyth price conf field is not checked in C.bad(bytes32,uint256) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#171-175) - - price = pyth.getEmaPriceNoOlderThan(id,age) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#172) +Pyth price conf field is not checked in C.bad2(C.Data) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#182-186) + - price = pyth.getEmaPriceNoOlderThan(data.id,data.age) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#183) + +Pyth price conf field is not checked in C.bad(bytes32,uint256) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#176-180) + - price = pyth.getEmaPriceNoOlderThan(id,age) (tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol#177) diff --git a/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedPublishTime_0_8_20_pyth_unchecked_publishtime_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedPublishTime_0_8_20_pyth_unchecked_publishtime_sol__0.txt index cb331c8d5..fa2f9e686 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedPublishTime_0_8_20_pyth_unchecked_publishtime_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_PythUncheckedPublishTime_0_8_20_pyth_unchecked_publishtime_sol__0.txt @@ -1,3 +1,6 @@ -Pyth price publishTime field is not checked in C.bad(bytes32) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#171-175) - - price = pyth.getEmaPriceUnsafe(id) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#172) +Pyth price publishTime field is not checked in C.bad(bytes32) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#175-179) + - price = pyth.getEmaPriceUnsafe(id) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#176) + +Pyth price publishTime field is not checked in C.bad2(C.Data) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#181-185) + - price = pyth.getEmaPriceUnsafe(data.id) (tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol#182) diff --git a/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol b/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol index 58880c382..9cdf648b2 100644 --- a/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol +++ b/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol @@ -164,6 +164,11 @@ interface IPyth { contract C { IPyth pyth; + struct Data { + bytes32 id; + uint256 age; + } + constructor(IPyth _pyth) { pyth = _pyth; } @@ -174,6 +179,12 @@ contract C { // Use price } + function bad2(Data calldata data) public { + PythStructs.Price memory price = pyth.getEmaPriceNoOlderThan(data.id, data.age); + require(price.publishTime > block.timestamp - 120); + // Use price + } + function good(bytes32 id, uint256 age) public { PythStructs.Price memory price = pyth.getEmaPriceNoOlderThan(id, age); require(price.conf < 10000); diff --git a/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol-0.8.20.zip b/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol-0.8.20.zip index 6e5fa1b9f..744bc1df0 100644 Binary files a/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol-0.8.20.zip and b/tests/e2e/detectors/test_data/pyth-unchecked-confidence/0.8.20/pyth_unchecked_confidence.sol-0.8.20.zip differ diff --git a/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol b/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol index 74ab10fe3..f1c2d1398 100644 --- a/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol +++ b/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol @@ -164,6 +164,10 @@ interface IPyth { contract C { IPyth pyth; + struct Data { + bytes32 id; + } + constructor(IPyth _pyth) { pyth = _pyth; } @@ -174,6 +178,12 @@ contract C { // Use price } + function bad2(Data calldata data) public { + PythStructs.Price memory price = pyth.getEmaPriceUnsafe(data.id); + require(price.conf < 10000); + // Use price + } + function good(bytes32 id) public { PythStructs.Price memory price = pyth.getEmaPriceUnsafe(id); require(price.publishTime > block.timestamp - 120); diff --git a/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol-0.8.20.zip b/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol-0.8.20.zip index 178b65b38..a3c8ece9e 100644 Binary files a/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol-0.8.20.zip and b/tests/e2e/detectors/test_data/pyth-unchecked-publishtime/0.8.20/pyth_unchecked_publishtime.sol-0.8.20.zip differ