#
tokens: 48789/50000 26/1140 files (page 8/103)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 8 of 103. Use http://codebase.md/cyfrin/aderyn?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .cargo
│   └── config.toml
├── .git-blame-ignore-revs
├── .gitattributes
├── .github
│   ├── images
│   │   ├── aderyn_logo.png
│   │   ├── poweredbycyfrinblack.png
│   │   └── poweredbycyfrinblue.png
│   ├── ISSUE_TEMPLATE
│   │   ├── bug_report.md
│   │   ├── false_positive_issue.md
│   │   └── feature_request.md
│   └── workflows
│       ├── cargo.yml
│       ├── dependencies.yml
│       ├── release.yml
│       ├── reports.yml
│       └── toml.yml
├── .gitignore
├── .gitmodules
├── .vscode
│   └── settings.json
├── aderyn
│   ├── Cargo.toml
│   ├── oranda.json
│   ├── README.md
│   ├── src
│   │   ├── birdsong.rs
│   │   ├── completions.rs
│   │   ├── lib.rs
│   │   ├── lsp.rs
│   │   ├── main.rs
│   │   ├── mcp.rs
│   │   └── panic.rs
│   └── templates
│       └── aderyn.toml
├── aderyn_core
│   ├── .gitignore
│   ├── Cargo.toml
│   ├── README.md
│   ├── src
│   │   ├── ast
│   │   │   ├── ast_nodes.rs
│   │   │   ├── ast.rs
│   │   │   ├── impls
│   │   │   │   ├── ctx
│   │   │   │   │   ├── utils.rs
│   │   │   │   │   └── workspace.rs
│   │   │   │   ├── ctx.rs
│   │   │   │   ├── disp
│   │   │   │   │   ├── blocks.rs
│   │   │   │   │   ├── contracts.rs
│   │   │   │   │   ├── enumerations.rs
│   │   │   │   │   ├── errors.rs
│   │   │   │   │   ├── events.rs
│   │   │   │   │   ├── expressions.rs
│   │   │   │   │   ├── functions.rs
│   │   │   │   │   ├── identifiers.rs
│   │   │   │   │   ├── literals.rs
│   │   │   │   │   ├── modifiers.rs
│   │   │   │   │   ├── statements.rs
│   │   │   │   │   ├── structures.rs
│   │   │   │   │   ├── types.rs
│   │   │   │   │   ├── user_defined_value_types.rs
│   │   │   │   │   ├── using_for_directives.rs
│   │   │   │   │   └── variables.rs
│   │   │   │   ├── disp.rs
│   │   │   │   ├── node
│   │   │   │   │   ├── blocks.rs
│   │   │   │   │   ├── contracts.rs
│   │   │   │   │   ├── documentation.rs
│   │   │   │   │   ├── enumerations.rs
│   │   │   │   │   ├── errors.rs
│   │   │   │   │   ├── events.rs
│   │   │   │   │   ├── expressions.rs
│   │   │   │   │   ├── functions.rs
│   │   │   │   │   ├── identifiers.rs
│   │   │   │   │   ├── import_directives.rs
│   │   │   │   │   ├── literals.rs
│   │   │   │   │   ├── modifiers.rs
│   │   │   │   │   ├── pragma_directives.rs
│   │   │   │   │   ├── source_units.rs
│   │   │   │   │   ├── statements.rs
│   │   │   │   │   ├── structures.rs
│   │   │   │   │   ├── types.rs
│   │   │   │   │   ├── user_defined_value_types.rs
│   │   │   │   │   ├── using_for_directives.rs
│   │   │   │   │   └── variables.rs
│   │   │   │   ├── node.rs
│   │   │   │   ├── own
│   │   │   │   │   ├── hashing.rs
│   │   │   │   │   ├── node_id.rs
│   │   │   │   │   ├── source_units.rs
│   │   │   │   │   └── utils.rs
│   │   │   │   └── own.rs
│   │   │   ├── impls.rs
│   │   │   ├── macros.rs
│   │   │   ├── magic.rs
│   │   │   ├── node_type.rs
│   │   │   └── yul.rs
│   │   ├── ast.rs
│   │   ├── audit
│   │   │   ├── attack_surface.rs
│   │   │   ├── auditor.rs
│   │   │   ├── entrypoint.rs
│   │   │   └── public_functions_no_sender.rs
│   │   ├── audit.rs
│   │   ├── context
│   │   │   ├── browser
│   │   │   │   ├── ancestral_line.rs
│   │   │   │   ├── closest_ancestor.rs
│   │   │   │   ├── external_calls.rs
│   │   │   │   ├── extractor.rs
│   │   │   │   ├── immediate_children.rs
│   │   │   │   ├── location.rs
│   │   │   │   ├── macros.rs
│   │   │   │   ├── parent.rs
│   │   │   │   ├── peek_over.rs
│   │   │   │   ├── peek_under.rs
│   │   │   │   ├── peek.rs
│   │   │   │   ├── siblings.rs
│   │   │   │   ├── sort_nodes.rs
│   │   │   │   └── storage_vars.rs
│   │   │   ├── browser.rs
│   │   │   ├── capturable.rs
│   │   │   ├── flow
│   │   │   │   ├── display.rs
│   │   │   │   ├── error.rs
│   │   │   │   ├── kind.rs
│   │   │   │   ├── primitives.rs
│   │   │   │   ├── reducibles.rs
│   │   │   │   ├── tests.rs
│   │   │   │   ├── utils.rs
│   │   │   │   ├── visualizer.rs
│   │   │   │   └── voids.rs
│   │   │   ├── flow.rs
│   │   │   ├── graph
│   │   │   │   ├── callgraph
│   │   │   │   │   ├── legacy.rs
│   │   │   │   │   ├── new.rs
│   │   │   │   │   ├── tests.rs
│   │   │   │   │   ├── utils.rs
│   │   │   │   │   └── visit.rs
│   │   │   │   ├── callgraph.rs
│   │   │   │   ├── preprocess
│   │   │   │   │   ├── legacy.rs
│   │   │   │   │   └── new.rs
│   │   │   │   ├── preprocess.rs
│   │   │   │   ├── traits.rs
│   │   │   │   └── utils.rs
│   │   │   ├── graph.rs
│   │   │   ├── macros.rs
│   │   │   ├── mcp
│   │   │   │   ├── callgraph
│   │   │   │   │   ├── render.rs
│   │   │   │   │   ├── tool.rs
│   │   │   │   │   └── utils.rs
│   │   │   │   ├── callgraph.rs
│   │   │   │   ├── contract_surface
│   │   │   │   │   ├── render.rs
│   │   │   │   │   ├── tool.rs
│   │   │   │   │   └── util.rs
│   │   │   │   ├── contract_surface.rs
│   │   │   │   ├── list_contracts
│   │   │   │   │   ├── render.rs
│   │   │   │   │   └── tool.rs
│   │   │   │   ├── list_contracts.rs
│   │   │   │   ├── node_finder
│   │   │   │   │   ├── render.rs
│   │   │   │   │   ├── tool.rs
│   │   │   │   │   └── utils.rs
│   │   │   │   ├── node_finder.rs
│   │   │   │   ├── node_summarizer
│   │   │   │   │   ├── render.rs
│   │   │   │   │   ├── tool.rs
│   │   │   │   │   └── utils.rs
│   │   │   │   ├── node_summarizer.rs
│   │   │   │   ├── project_overview
│   │   │   │   │   ├── render.rs
│   │   │   │   │   └── tool.rs
│   │   │   │   ├── project_overview.rs
│   │   │   │   ├── tool_guide
│   │   │   │   │   └── tool.rs
│   │   │   │   └── tool_guide.rs
│   │   │   ├── mcp.rs
│   │   │   ├── router
│   │   │   │   ├── external_calls.rs
│   │   │   │   ├── internal_calls.rs
│   │   │   │   ├── modifier_calls.rs
│   │   │   │   └── tests.rs
│   │   │   ├── router.rs
│   │   │   └── workspace.rs
│   │   ├── context.rs
│   │   ├── detect
│   │   │   ├── detector.rs
│   │   │   ├── entrypoint.rs
│   │   │   ├── helpers.rs
│   │   │   ├── high
│   │   │   │   ├── _template.rs
│   │   │   │   ├── abi_encode_packed_hash_collision.rs
│   │   │   │   ├── arbitrary_transfer_from.rs
│   │   │   │   ├── const_func_changes_state.rs
│   │   │   │   ├── contract_locks_ether.rs
│   │   │   │   ├── dangerous_unary_operator.rs
│   │   │   │   ├── delegate_call_unchecked_address.rs
│   │   │   │   ├── delete_nested_mapping.rs
│   │   │   │   ├── dynamic_array_length_assignment.rs
│   │   │   │   ├── enumerable_loop_removal.rs
│   │   │   │   ├── eth_send_unchecked_address.rs
│   │   │   │   ├── experimental_encoder.rs
│   │   │   │   ├── function_selector_collision.rs
│   │   │   │   ├── incorrect_caret_operator.rs
│   │   │   │   ├── incorrect_erc20_interface.rs
│   │   │   │   ├── incorrect_erc721_interface.rs
│   │   │   │   ├── incorrect_shift_order.rs
│   │   │   │   ├── misused_boolean.rs
│   │   │   │   ├── msg_value_in_loops.rs
│   │   │   │   ├── multiple_constructors.rs
│   │   │   │   ├── nested_struct_in_mapping.rs
│   │   │   │   ├── out_of_order_retryable.rs
│   │   │   │   ├── pre_declared_variable_usage.rs
│   │   │   │   ├── reentrancy_state_change.rs
│   │   │   │   ├── reused_contract_name.rs
│   │   │   │   ├── rtlo.rs
│   │   │   │   ├── selfdestruct.rs
│   │   │   │   ├── signed_integer_storage_array.rs
│   │   │   │   ├── state_variable_shadowing.rs
│   │   │   │   ├── storage_array_memory_edit.rs
│   │   │   │   ├── strict_equality_contract_balance.rs
│   │   │   │   ├── tautological_compare.rs
│   │   │   │   ├── tautology_or_contradiction.rs
│   │   │   │   ├── tx_origin_used_for_auth.rs
│   │   │   │   ├── unchecked_low_level_call.rs
│   │   │   │   ├── unchecked_send.rs
│   │   │   │   ├── unprotected_initializer.rs
│   │   │   │   ├── unsafe_casting.rs
│   │   │   │   ├── weak_randomness.rs
│   │   │   │   └── yul_return.rs
│   │   │   ├── high.rs
│   │   │   ├── low
│   │   │   │   ├── _template.rs
│   │   │   │   ├── assert_state_change.rs
│   │   │   │   ├── block_timestamp_deadline.rs
│   │   │   │   ├── boolean_equality.rs
│   │   │   │   ├── builtin_symbol_shadowing.rs
│   │   │   │   ├── centralization_risk.rs
│   │   │   │   ├── constant_function_contains_assembly.rs
│   │   │   │   ├── costly_loop.rs
│   │   │   │   ├── dead_code.rs
│   │   │   │   ├── delegatecall_in_loop.rs
│   │   │   │   ├── deprecated_oz_function.rs
│   │   │   │   ├── division_before_multiplication.rs
│   │   │   │   ├── ecrecover.rs
│   │   │   │   ├── empty_block.rs
│   │   │   │   ├── empty_require_revert.rs
│   │   │   │   ├── function_initializing_state.rs
│   │   │   │   ├── function_pointer_in_constructor.rs
│   │   │   │   ├── inconsistent_type_names.rs
│   │   │   │   ├── incorrect_modifier.rs
│   │   │   │   ├── internal_function_used_once.rs
│   │   │   │   ├── large_numeric_literal.rs
│   │   │   │   ├── literal_instead_of_constant.rs
│   │   │   │   ├── local_variable_shadowing.rs
│   │   │   │   ├── missing_inheritance.rs
│   │   │   │   ├── modifier_used_only_once.rs
│   │   │   │   ├── multiple_placeholders.rs
│   │   │   │   ├── non_reentrant_not_first.rs
│   │   │   │   ├── push_0_opcode.rs
│   │   │   │   ├── redundant_statement.rs
│   │   │   │   ├── require_revert_in_loop.rs
│   │   │   │   ├── return_bomb.rs
│   │   │   │   ├── solmate_safe_transfer_lib.rs
│   │   │   │   ├── state_change_without_event.rs
│   │   │   │   ├── state_no_address_check.rs
│   │   │   │   ├── state_variable_could_be_constant.rs
│   │   │   │   ├── state_variable_could_be_immutable.rs
│   │   │   │   ├── state_variable_read_external.rs
│   │   │   │   ├── storage_array_length_not_cached.rs
│   │   │   │   ├── todo.rs
│   │   │   │   ├── unchecked_return.rs
│   │   │   │   ├── uninitialized_local_variable.rs
│   │   │   │   ├── unsafe_erc20_operation.rs
│   │   │   │   ├── unsafe_oz_erc721_mint.rs
│   │   │   │   ├── unspecific_solidity_pragma.rs
│   │   │   │   ├── unused_error.rs
│   │   │   │   ├── unused_import.rs
│   │   │   │   ├── unused_public_function.rs
│   │   │   │   ├── unused_state_variable.rs
│   │   │   │   └── void_constructor.rs
│   │   │   ├── low.rs
│   │   │   └── test_utils.rs
│   │   ├── detect.rs
│   │   ├── lib.rs
│   │   ├── stats
│   │   │   ├── cloc.rs
│   │   │   ├── dbg_tips.txt
│   │   │   ├── ignore.rs
│   │   │   ├── token.rs
│   │   │   └── util.rs
│   │   ├── stats.rs
│   │   ├── test_utils
│   │   │   └── load_source_unit.rs
│   │   ├── test_utils.rs
│   │   ├── visitor
│   │   │   ├── ast_visitor.rs
│   │   │   ├── macros.rs
│   │   │   └── workspace_visitor.rs
│   │   └── visitor.rs
│   ├── templates
│   │   └── mcp-tool-response
│   │       ├── callgraph.md
│   │       ├── contract_surface.md
│   │       ├── list_contracts.md
│   │       ├── node_finder_get_all.md
│   │       ├── node_finder_grep.md
│   │       ├── node_finder_search.md
│   │       ├── node_summarizer.md
│   │       ├── project_overview.md
│   │       └── tool_guide.md
│   └── tests
│       ├── common
│       │   ├── ancestral_line.rs
│       │   ├── closest_ancestor.rs
│       │   ├── immediate_children.rs
│       │   ├── immediate_parent.rs
│       │   ├── mod.rs
│       │   ├── new_ast_nodes.rs
│       │   ├── peek_over.rs
│       │   └── sibling.rs
│       └── traversal.rs
├── aderyn_driver
│   ├── .gitignore
│   ├── benches
│   │   └── detectors.rs
│   ├── Cargo.toml
│   ├── README.md
│   ├── src
│   │   ├── compile.rs
│   │   ├── config.rs
│   │   ├── display.rs
│   │   ├── driver.rs
│   │   ├── interface
│   │   │   ├── json.rs
│   │   │   ├── lsp.rs
│   │   │   ├── markdown.rs
│   │   │   ├── mod.rs
│   │   │   ├── sarif.rs
│   │   │   ├── tables.rs
│   │   │   └── util.rs
│   │   ├── lib.rs
│   │   ├── mcp.rs
│   │   ├── process.rs
│   │   └── runner.rs
│   └── tests
│       └── astgen.rs
├── bacon.toml
├── benchmarks
│   ├── aderyn
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── iteration_times.svg
│   │       │   └── pdf.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── iteration_times_small.svg
│   │       ├── iteration_times.svg
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── relative_iteration_times_small.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── SD.svg
│   │       └── typical.svg
│   ├── arbitrary-transfer-from
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── avoid-abi-encode-packed
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── block-timestamp-deadline
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── centralization-risk
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── constants-instead-of-literals
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── delegate-call-in-loop
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── deprecated-oz-functions
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── ecrecover
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── empty-block
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── hello_world
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── inconsistent-type-names
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── large-numeric-literal
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── non-reentrant-before-others
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── push-zero-opcode
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── report
│   │   └── index.html
│   ├── require-with-string
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── solmate-safe-transfer-lib
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── unindexed-events
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── unprotected-initializer
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── unsafe-erc20-functions
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── unsafe-oz-erc721-mint
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── unspecific-solidity-pragma
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── useless-internal-function
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── useless-modifier
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   ├── useless-public-function
│   │   ├── base
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   ├── change
│   │   │   └── estimates.json
│   │   ├── new
│   │   │   ├── benchmark.json
│   │   │   ├── estimates.json
│   │   │   ├── sample.json
│   │   │   └── tukey.json
│   │   └── report
│   │       ├── both
│   │       │   ├── pdf.svg
│   │       │   └── regression.svg
│   │       ├── change
│   │       │   ├── mean.svg
│   │       │   ├── median.svg
│   │       │   └── t-test.svg
│   │       ├── index.html
│   │       ├── MAD.svg
│   │       ├── mean.svg
│   │       ├── median.svg
│   │       ├── pdf_small.svg
│   │       ├── pdf.svg
│   │       ├── regression_small.svg
│   │       ├── regression.svg
│   │       ├── relative_pdf_small.svg
│   │       ├── relative_regression_small.svg
│   │       ├── SD.svg
│   │       ├── slope.svg
│   │       └── typical.svg
│   └── zero-address-check
│       ├── base
│       │   ├── benchmark.json
│       │   ├── estimates.json
│       │   ├── sample.json
│       │   └── tukey.json
│       ├── change
│       │   └── estimates.json
│       ├── new
│       │   ├── benchmark.json
│       │   ├── estimates.json
│       │   ├── sample.json
│       │   └── tukey.json
│       └── report
│           ├── both
│           │   ├── pdf.svg
│           │   └── regression.svg
│           ├── change
│           │   ├── mean.svg
│           │   ├── median.svg
│           │   └── t-test.svg
│           ├── index.html
│           ├── MAD.svg
│           ├── mean.svg
│           ├── median.svg
│           ├── pdf_small.svg
│           ├── pdf.svg
│           ├── regression_small.svg
│           ├── regression.svg
│           ├── relative_pdf_small.svg
│           ├── relative_regression_small.svg
│           ├── SD.svg
│           ├── slope.svg
│           └── typical.svg
├── Cargo.lock
├── Cargo.toml
├── cli
│   ├── benchmarks.sh
│   └── reportgen.sh
├── CODEOWNERS
├── CONTRIBUTING.md
├── cyfrinup
│   ├── dynamic_script
│   └── why.md
├── deny.toml
├── dist-workspace.toml
├── funding.json
├── LICENSE
├── Makefile
├── package-lock.json
├── package.json
├── README.md
├── RELEASE_CHECKLIST.md
├── reports
│   ├── adhoc-sol-files-highs-only-report.json
│   ├── adhoc-sol-files-report.md
│   ├── ccip-functions-report.md
│   ├── empty_report.md
│   ├── hardhat-playground-report.md
│   ├── nft-report-icm.md
│   ├── nft-report.md
│   ├── prb-math-report.md
│   ├── report.json
│   ├── report.md
│   ├── report.sarif
│   ├── sablier-aderyn-toml-nested-root.md
│   ├── templegold-report.md
│   └── uniswap_profile.md
├── rust-toolchain.toml
├── rustfmt.toml
├── tests
│   ├── adhoc-sol-files
│   │   ├── aderyn.toml
│   │   ├── Counter.sol
│   │   ├── DemoASTNodes.sol
│   │   ├── Helper.sol
│   │   ├── InconsistentUints.sol
│   │   ├── inheritance
│   │   │   ├── ExtendedInheritance.sol
│   │   │   ├── IContractInheritance.sol
│   │   │   └── InheritanceBase.sol
│   │   ├── InternalFunctions.sol
│   │   ├── lib
│   │   │   └── ThisShouldBeExcluded.sol
│   │   ├── multiple-versions
│   │   │   ├── 0.4
│   │   │   │   ├── A.sol
│   │   │   │   └── B.sol
│   │   │   ├── 0.5
│   │   │   │   ├── A.sol
│   │   │   │   └── B.sol
│   │   │   ├── 0.6
│   │   │   │   ├── A.sol
│   │   │   │   └── B.sol
│   │   │   ├── 0.7
│   │   │   │   ├── A.sol
│   │   │   │   └── B.sol
│   │   │   └── 0.8
│   │   │       ├── A.sol
│   │   │       └── B.sol
│   │   ├── OnceModifierExample.sol
│   │   └── StateVariables.sol
│   ├── ast
│   │   ├── abstract_contract.json
│   │   ├── address_payable.json
│   │   ├── array_type_name.json
│   │   ├── ast-erc4626.json
│   │   ├── base_constructor_call.json
│   │   ├── bit_not.json
│   │   ├── call.json
│   │   ├── constructor.json
│   │   ├── contract_dep_order.json
│   │   ├── do_while.json
│   │   ├── documentation_1.json
│   │   ├── documentation_2.json
│   │   ├── documentation_3.json
│   │   ├── documentation_local_variable.json
│   │   ├── documentation_on_statements.json
│   │   ├── documentation_triple.json
│   │   ├── empty_block.json
│   │   ├── enum_value_declaration.json
│   │   ├── enum_value.json
│   │   ├── event_definition.json
│   │   ├── experimental_encoder_pragma.json
│   │   ├── fallback_and_reveice_ether.json
│   │   ├── fallback_payable.json
│   │   ├── fallback.json
│   │   ├── function_type.json
│   │   ├── function.json
│   │   ├── global_enum.json
│   │   ├── global_struct.json
│   │   ├── inheritance_specifier.json
│   │   ├── leave.json
│   │   ├── license.json
│   │   ├── long_type_name_binary_operation.json
│   │   ├── long_type_name_identifier.json
│   │   ├── loop.json
│   │   ├── mappings.json
│   │   ├── modifier_definition.json
│   │   ├── modifier_invocation.json
│   │   ├── mutability.json
│   │   ├── nested_functions.json
│   │   ├── non_utf8.json
│   │   ├── override.json
│   │   ├── placeholder_statement.json
│   │   ├── receive_ether.json
│   │   ├── short_type_name_ref.json
│   │   ├── short_type_name.json
│   │   ├── slot_offset.json
│   │   ├── smoke.json
│   │   ├── source_location.json
│   │   ├── string.json
│   │   ├── stringlit.json
│   │   ├── switch_default.json
│   │   ├── switch.json
│   │   ├── try_catch.json
│   │   ├── two_base_functions.json
│   │   ├── unicode.json
│   │   ├── used_errors.json
│   │   ├── userDefinedValueType.json
│   │   ├── using_for_directive.json
│   │   ├── var_access.json
│   │   └── yul_hex_literal.json
│   ├── contract-playground
│   │   ├── .github
│   │   │   └── workflows
│   │   │       └── test.yml
│   │   ├── .gitignore
│   │   ├── dot
│   │   │   └── .gitkeep
│   │   ├── foundry.toml
│   │   ├── README.md
│   │   ├── script
│   │   │   └── Counter.s.sol
│   │   ├── src
│   │   │   ├── AbstractContract.sol
│   │   │   ├── AderynIgnoreCustomDetectors.sol
│   │   │   ├── AdminContract.sol
│   │   │   ├── ArbitraryTransferFrom.sol
│   │   │   ├── AssemblyExample.sol
│   │   │   ├── AssertStateChange.sol
│   │   │   ├── auditor_mode
│   │   │   │   ├── ExternalCalls.sol
│   │   │   │   └── PublicFunctionsWithoutSenderCheck.sol
│   │   │   ├── BooleanEquality.sol
│   │   │   ├── BuiltinSymbolShadow.sol
│   │   │   ├── CacheArrayLength.sol
│   │   │   ├── CallGraphTests.sol
│   │   │   ├── Casting.sol
│   │   │   ├── cloc
│   │   │   │   ├── AnotherHeavilyCommentedContract.sol
│   │   │   │   ├── EmptyContractFile.sol
│   │   │   │   └── HeavilyCommentedContract.sol
│   │   │   ├── CompilerBugStorageSignedIntegerArray.sol
│   │   │   ├── ConstantFuncsAssembly.sol
│   │   │   ├── ConstantsLiterals.sol
│   │   │   ├── ConstFuncChangeState.sol
│   │   │   ├── ContractLocksEther.sol
│   │   │   ├── ContractWithTodo.sol
│   │   │   ├── control_flow
│   │   │   │   └── SimpleProgram.sol
│   │   │   ├── CostlyOperationsInsideLoops.sol
│   │   │   ├── Counter.sol
│   │   │   ├── CrazyPragma.sol
│   │   │   ├── DangerousStrictEquality1.sol
│   │   │   ├── DangerousStrictEquality2.sol
│   │   │   ├── DangerousUnaryOperator.sol
│   │   │   ├── DeadCode.sol
│   │   │   ├── DelegateCallWithoutAddressCheck.sol
│   │   │   ├── DeletionNestedMappingStructureContract.sol
│   │   │   ├── DeprecatedOZFunctions.sol
│   │   │   ├── DivisionBeforeMultiplication.sol
│   │   │   ├── DynamicArrayLengthAssignment.sol
│   │   │   ├── EmitAfterExternalCall.sol
│   │   │   ├── EmptyBlocks.sol
│   │   │   ├── EnumerableSetIteration.sol
│   │   │   ├── eth2
│   │   │   │   └── DepositContract.sol
│   │   │   ├── ExperimentalEncoder.sol
│   │   │   ├── ExternalCalls.sol
│   │   │   ├── FunctionInitializingState.sol
│   │   │   ├── FunctionPointers.sol
│   │   │   ├── FunctionSignatureCollision.sol
│   │   │   ├── HugeConstants.sol
│   │   │   ├── IgnoreEverything.sol
│   │   │   ├── InconsistentUints.sol
│   │   │   ├── IncorrectCaretOperator.sol
│   │   │   ├── IncorrectERC20.sol
│   │   │   ├── IncorrectERC721.sol
│   │   │   ├── IncorrectModifier.sol
│   │   │   ├── IncorrectShift.sol
│   │   │   ├── inheritance
│   │   │   │   ├── ExtendedInheritance.sol
│   │   │   │   ├── IContractInheritance.sol
│   │   │   │   └── InheritanceBase.sol
│   │   │   ├── InternalFunctions.sol
│   │   │   ├── KeccakContract.sol
│   │   │   ├── LocalVariableShadow.sol
│   │   │   ├── MissingInheritance.sol
│   │   │   ├── MisusedBoolean.sol
│   │   │   ├── MsgValueInLoop.sol
│   │   │   ├── MultipleConstructorSchemes.sol
│   │   │   ├── MultiplePlaceholders.sol
│   │   │   ├── nested
│   │   │   │   ├── 1
│   │   │   │   │   └── Nested.sol
│   │   │   │   └── 2
│   │   │   │       └── Nested.sol
│   │   │   ├── nested_mappings
│   │   │   │   ├── LaterVersion.sol
│   │   │   │   └── NestedMappings.sol
│   │   │   ├── OnceModifierExample.sol
│   │   │   ├── OnlyLibrary.sol
│   │   │   ├── OutOfOrderRetryable.sol
│   │   │   ├── parent_chain
│   │   │   │   └── ParentChainContract.sol
│   │   │   ├── PragmaRange.sol
│   │   │   ├── PreDeclaredVarUsage.sol
│   │   │   ├── PublicFunction.sol
│   │   │   ├── PublicVariableReadInExternalContext.sol
│   │   │   ├── RedundantStatements.sol
│   │   │   ├── ReturnBomb.sol
│   │   │   ├── reused_contract_name
│   │   │   │   ├── ContractA.sol
│   │   │   │   └── ContractB.sol
│   │   │   ├── RevertsAndRequriesInLoops.sol
│   │   │   ├── router
│   │   │   │   ├── ExternalCalls.sol
│   │   │   │   ├── FallbackAndReceiveOverrides.sol
│   │   │   │   ├── InternalCalls.sol
│   │   │   │   ├── ModifierCalls.sol
│   │   │   │   └── VarOverridesFunction.sol
│   │   │   ├── RTLO.sol
│   │   │   ├── SendEtherNoChecks.sol
│   │   │   ├── SendEtherNoChecksLibImport.sol
│   │   │   ├── StateChangeAfterExternalCall.sol
│   │   │   ├── StateShadowing.sol
│   │   │   ├── StateVariableCouldBeDeclaredConstant.sol
│   │   │   ├── StateVariableCouldBeDeclaredImmutable.sol
│   │   │   ├── StateVariables.sol
│   │   │   ├── StateVariablesChangesWithoutEvents.sol
│   │   │   ├── StateVariablesManipulation.sol
│   │   │   ├── StorageConditionals.sol
│   │   │   ├── StorageParameters.sol
│   │   │   ├── T11sTranferer.sol
│   │   │   ├── TautologicalCompare.sol
│   │   │   ├── TautologyOrContradiction.sol
│   │   │   ├── TestERC20.sol
│   │   │   ├── TransientKeyword.sol
│   │   │   ├── Trump.sol
│   │   │   ├── TxOriginUsedForAuth.sol
│   │   │   ├── U2.sol
│   │   │   ├── U3.sol
│   │   │   ├── U4.sol
│   │   │   ├── U5.sol
│   │   │   ├── UncheckedCalls.sol
│   │   │   ├── UncheckedReturn.sol
│   │   │   ├── UncheckedSend.sol
│   │   │   ├── UninitializedLocalVariables.sol
│   │   │   ├── UninitializedStateVariable.sol
│   │   │   ├── uniswap
│   │   │   │   ├── UniswapV2Swapper.sol
│   │   │   │   └── UniswapV3Swapper.sol
│   │   │   ├── UnprotectedInitialize.sol
│   │   │   ├── UnsafeERC721Mint.sol
│   │   │   ├── UnusedError.sol
│   │   │   ├── UnusedImport.sol
│   │   │   ├── UnusedStateVariables.sol
│   │   │   ├── UsingSelfdestruct.sol
│   │   │   ├── VoidConstructor.sol
│   │   │   ├── WeakRandomness.sol
│   │   │   ├── WrongOrderOfLayout.sol
│   │   │   ├── YulReturn.sol
│   │   │   └── ZeroAddressCheck.sol
│   │   └── test
│   │       └── Counter.t.sol
│   ├── foundry-nft-f23
│   │   ├── .github
│   │   │   └── workflows
│   │   │       └── test.yml
│   │   ├── .gitignore
│   │   ├── foundry.lock
│   │   ├── foundry.toml
│   │   ├── README.md
│   │   ├── remappings.txt
│   │   └── src
│   │       ├── BasicNft.sol
│   │       ├── F1.sol
│   │       ├── F2.sol
│   │       ├── Initializer.sol
│   │       └── inner-core-modules
│   │           └── ICM.sol
│   ├── foundry-nft-f23-icm
│   │   ├── .github
│   │   │   └── workflows
│   │   │       └── test.yml
│   │   ├── .gitignore
│   │   ├── aderyn.toml
│   │   ├── foundry.toml
│   │   ├── README.md
│   │   ├── remappings.txt
│   │   └── src
│   │       ├── BasicNft.sol
│   │       ├── F1.sol
│   │       ├── F2.sol
│   │       ├── Initializer.sol
│   │       └── inner-core-modules
│   │           └── ICM.sol
│   ├── hardhat-js-playground
│   │   ├── .gitignore
│   │   ├── artifacts
│   │   │   ├── build-info
│   │   │   │   └── cee6fe9a9a2f03f7ff10a27ab2746af6.json
│   │   │   └── contracts
│   │   │       ├── Counter.sol
│   │   │       │   ├── Counter.dbg.json
│   │   │       │   └── Counter.json
│   │   │       ├── ExtendedInheritance.sol
│   │   │       │   ├── ExtendedInheritance.dbg.json
│   │   │       │   └── ExtendedInheritance.json
│   │   │       ├── IContractInheritance.sol
│   │   │       │   ├── IContractInheritance.dbg.json
│   │   │       │   └── IContractInheritance.json
│   │   │       ├── InheritanceBase.sol
│   │   │       │   ├── InheritanceBase.dbg.json
│   │   │       │   └── InheritanceBase.json
│   │   │       ├── KeccakContract.sol
│   │   │       │   ├── KeccakContract.dbg.json
│   │   │       │   └── KeccakContract.json
│   │   │       ├── Lock.sol
│   │   │       │   ├── Lock.dbg.json
│   │   │       │   └── Lock.json
│   │   │       └── StateVariables.sol
│   │   │           ├── StateVariables.dbg.json
│   │   │           └── StateVariables.json
│   │   ├── contracts
│   │   │   ├── Counter.sol
│   │   │   ├── ExtendedInheritance.sol
│   │   │   ├── IContractInheritance.sol
│   │   │   ├── InheritanceBase.sol
│   │   │   ├── KeccakContract.sol
│   │   │   ├── Lock.sol
│   │   │   └── StateVariables.sol
│   │   ├── hardhat.config.js
│   │   ├── package.json
│   │   ├── README.md
│   │   ├── scripts
│   │   │   └── deploy.js
│   │   ├── test
│   │   │   └── Lock.js
│   │   └── yarn.lock
│   ├── no-sol-files
│   │   ├── extra
│   │   │   └── HelloAgain.md
│   │   ├── Hello.txt
│   │   └── Hello.yul
│   └── toml
│       ├── nested_project1
│       │   ├── aderyn.toml
│       │   ├── folder1
│       │   │   └── hardhat.config.ts
│       │   ├── folder2
│       │   │   └── hardhat.config.ts
│       │   └── folder3
│       │       └── file.txt
│       └── nested_project2
│           ├── aderyn.toml
│           ├── folder1
│           │   └── foundry.toml
│           └── folder2
│               └── file1.txt
├── tools
│   └── xtask
│       ├── Cargo.toml
│       └── src
│           ├── blesspr.rs
│           ├── cut_release.rs
│           ├── flags.rs
│           ├── main.rs
│           ├── reportgen.rs
│           └── tomlgen.rs
└── typos.toml
```

# Files

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/enumerable_loop_removal.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, error::Error};
  2 | 
  3 | use crate::ast::{NodeID, NodeType};
  4 | 
  5 | use crate::{
  6 |     capture,
  7 |     context::{
  8 |         browser::{ExtractMemberAccesses, GetClosestAncestorOfTypeX},
  9 |         workspace::WorkspaceContext,
 10 |     },
 11 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 12 | };
 13 | use eyre::Result;
 14 | 
 15 | #[derive(Default)]
 16 | pub struct EnumerableLoopRemovalDetector {
 17 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 18 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 19 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 20 | }
 21 | 
 22 | impl IssueDetector for EnumerableLoopRemovalDetector {
 23 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 24 |         // Find MemberAccesses with name `remove` and
 25 |         // typeDescriptions.typeString.contains(EnumerableSet) for each one
 26 |         // Find the closest ancestor of a loop
 27 |         // if it exists, extract all `at` member accesses on the enumerableset
 28 |         // If an `at` memberaccess also exists in the loop, add the remove to found_instances
 29 | 
 30 |         context
 31 |             .member_accesses()
 32 |             .into_iter()
 33 |             .filter(|member_access| {
 34 |                 member_access.member_name == "remove"
 35 |                     && member_access
 36 |                         .type_descriptions
 37 |                         .type_string
 38 |                         .as_ref()
 39 |                         .is_some_and(|type_string| type_string.contains("EnumerableSet"))
 40 |             })
 41 |             .for_each(|member_access| {
 42 |                 let parent_loops = [
 43 |                     member_access.closest_ancestor_of_type(context, NodeType::ForStatement),
 44 |                     member_access.closest_ancestor_of_type(context, NodeType::WhileStatement),
 45 |                     member_access.closest_ancestor_of_type(context, NodeType::DoWhileStatement),
 46 |                 ];
 47 |                 for parent_loop in parent_loops.into_iter().flatten() {
 48 |                     ExtractMemberAccesses::from(parent_loop).extracted.into_iter().for_each(
 49 |                         |at_member_access| {
 50 |                             if at_member_access.member_name == "at" {
 51 |                                 capture!(self, context, member_access);
 52 |                             }
 53 |                         },
 54 |                     );
 55 |                 }
 56 |             });
 57 | 
 58 |         Ok(!self.found_instances.is_empty())
 59 |     }
 60 | 
 61 |     fn severity(&self) -> IssueSeverity {
 62 |         IssueSeverity::High
 63 |     }
 64 | 
 65 |     fn title(&self) -> String {
 66 |         String::from("EnumerableSet.remove Corrupts Order")
 67 |     }
 68 | 
 69 |     fn description(&self) -> String {
 70 |         String::from("If the order of an EnumerableSet is required, removing items in a loop using `at` and `remove` corrupts this order.
 71 | Consider using a different data structure or removing items by collecting them during the loop, then removing after the loop.")
 72 |     }
 73 | 
 74 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 75 |         self.found_instances.clone()
 76 |     }
 77 | 
 78 |     fn name(&self) -> String {
 79 |         format!("{}", IssueDetectorNamePool::EnumerableLoopRemoval)
 80 |     }
 81 | }
 82 | 
 83 | #[cfg(test)]
 84 | mod enuemrable_loop_removal_tests {
 85 | 
 86 |     use crate::detect::{detector::IssueDetector, high::EnumerableLoopRemovalDetector};
 87 | 
 88 |     #[test]
 89 | 
 90 |     fn test_enumerable_loop_detector() {
 91 |         let context = crate::detect::test_utils::load_solidity_source_unit(
 92 |             "../tests/contract-playground/src/EnumerableSetIteration.sol",
 93 |         );
 94 | 
 95 |         let mut detector = EnumerableLoopRemovalDetector::default();
 96 |         let found = detector.detect(&context).unwrap();
 97 |         assert!(found);
 98 |         assert_eq!(detector.instances().len(), 5);
 99 |     }
100 | }
101 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/deprecated_oz_function.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, error::Error};
  2 | 
  3 | use crate::{
  4 |     ast::{NodeID, NodeType},
  5 |     capture,
  6 |     context::{
  7 |         browser::GetClosestAncestorOfTypeX,
  8 |         workspace::{ASTNode, WorkspaceContext},
  9 |     },
 10 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 11 | };
 12 | use eyre::Result;
 13 | 
 14 | #[derive(Default)]
 15 | pub struct DeprecatedOZFunctionDetector {
 16 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 17 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 18 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 19 | }
 20 | 
 21 | impl IssueDetector for DeprecatedOZFunctionDetector {
 22 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 23 |         for identifier in context.identifiers() {
 24 |             // if source_unit has any ImportDirectives with absolute_path containing "openzeppelin"
 25 |             // call identifier.accept(self)
 26 |             if let Some(ASTNode::SourceUnit(source_unit)) =
 27 |                 identifier.closest_ancestor_of_type(context, NodeType::SourceUnit)
 28 |             {
 29 |                 let import_directives = source_unit.import_directives();
 30 |                 if import_directives.iter().any(|directive| {
 31 |                     directive
 32 |                         .absolute_path
 33 |                         .as_ref()
 34 |                         .is_some_and(|path| path.contains("openzeppelin"))
 35 |                 }) && identifier.name == "_setupRole"
 36 |                 {
 37 |                     capture!(self, context, identifier);
 38 |                 }
 39 |             } else {
 40 |                 // Optional: handle other cases, or do nothing
 41 |             }
 42 |         }
 43 |         for member_access in context.member_accesses() {
 44 |             // if source_unit has any ImportDirectives with absolute_path containing "openzeppelin"
 45 |             // call member_access.accept(self)
 46 |             if let Some(ASTNode::SourceUnit(source_unit)) =
 47 |                 member_access.closest_ancestor_of_type(context, NodeType::SourceUnit)
 48 |             {
 49 |                 let import_directives = source_unit.import_directives();
 50 |                 if import_directives.iter().any(|directive| {
 51 |                     directive
 52 |                         .absolute_path
 53 |                         .as_ref()
 54 |                         .is_some_and(|path| path.contains("openzeppelin"))
 55 |                 }) && member_access.member_name == "safeApprove"
 56 |                 {
 57 |                     capture!(self, context, member_access);
 58 |                 }
 59 |             }
 60 |         }
 61 |         Ok(!self.found_instances.is_empty())
 62 |     }
 63 | 
 64 |     fn title(&self) -> String {
 65 |         String::from("Deprecated OpenZeppelin Function")
 66 |     }
 67 | 
 68 |     fn description(&self) -> String {
 69 |         String::from(
 70 |             "Openzeppelin has deprecated several functions and replaced with newer versions. Please consult https://docs.openzeppelin.com/",
 71 |         )
 72 |     }
 73 | 
 74 |     fn severity(&self) -> IssueSeverity {
 75 |         IssueSeverity::Low
 76 |     }
 77 | 
 78 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 79 |         self.found_instances.clone()
 80 |     }
 81 | 
 82 |     fn name(&self) -> String {
 83 |         format!("{}", IssueDetectorNamePool::DeprecatedOzFunction)
 84 |     }
 85 | }
 86 | 
 87 | #[cfg(test)]
 88 | mod deprecated_oz_functions_tests {
 89 | 
 90 |     use crate::detect::detector::IssueDetector;
 91 | 
 92 |     use super::DeprecatedOZFunctionDetector;
 93 | 
 94 |     #[test]
 95 | 
 96 |     fn test_deprecated_oz_functions_detector_by_loading_contract_directly() {
 97 |         let context = crate::detect::test_utils::load_solidity_source_unit(
 98 |             "../tests/contract-playground/src/DeprecatedOZFunctions.sol",
 99 |         );
100 | 
101 |         let mut detector = DeprecatedOZFunctionDetector::default();
102 |         let found = detector.detect(&context).unwrap();
103 |         assert!(found);
104 |         assert_eq!(detector.instances().len(), 2);
105 |     }
106 | }
107 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/context/mcp/contract_surface/tool.rs:
--------------------------------------------------------------------------------

```rust
  1 | use super::render::*;
  2 | use crate::{
  3 |     ast::{ASTNode, NodeID},
  4 |     context::{
  5 |         macros::{mcp_error, mcp_success},
  6 |         mcp::{
  7 |             MCPToolNamePool, ModelContextProtocolState, ModelContextProtocolTool,
  8 |             contract_surface::util::{
  9 |                 get_classified_entrypoint_functions, get_inheritance_chain_info,
 10 |                 get_total_state_variables,
 11 |             },
 12 |         },
 13 |     },
 14 | };
 15 | use indoc::indoc;
 16 | use rmcp::{
 17 |     ErrorData as McpError, handler::server::wrapper::Parameters, model::CallToolResult, schemars,
 18 | };
 19 | use serde::Deserialize;
 20 | use std::sync::Arc;
 21 | 
 22 | #[derive(Clone)]
 23 | pub struct ContractSurfaceTool {
 24 |     state: Arc<ModelContextProtocolState>,
 25 | }
 26 | 
 27 | #[derive(Deserialize, schemars::JsonSchema)]
 28 | pub struct ContractSurfacePayload {
 29 |     /// The index of the compilation unit to analyze. Must be a positive integer starting from 1.
 30 |     /// Use the project overview tool first to see all available compilation units and their
 31 |     /// indices.
 32 |     pub compilation_unit_index: usize,
 33 |     /// The Node ID of the specific contract to analyze. Obtain this from the list contracts tool,
 34 |     /// which returns Node IDs for all deployable contracts in the compilation unit. Each contract
 35 |     /// has a unique Node ID within its compilation unit.
 36 |     pub node_id: NodeID,
 37 | }
 38 | 
 39 | impl ModelContextProtocolTool for ContractSurfaceTool {
 40 |     type Input = ContractSurfacePayload;
 41 | 
 42 |     fn new(state: Arc<ModelContextProtocolState>) -> Self {
 43 |         Self { state }
 44 |     }
 45 | 
 46 |     fn name(&self) -> String {
 47 |         MCPToolNamePool::AderynContractSurfaceInspector.to_string()
 48 |     }
 49 | 
 50 |     fn description(&self) -> String {
 51 |         indoc! {
 52 |             "Analyzes the surface area of a specific deployable contract within a compilation unit. Returns details\
 53 |             such as contract's state variables (own and inherited), and all entrypoint functions (own and inherited).\
 54 |             Use the Node ID from the list contracts tool to specify which contract to analyze."
 55 |         }
 56 |         .to_string()
 57 |     }
 58 | 
 59 |     fn execute(&self, input: Parameters<Self::Input>) -> Result<CallToolResult, McpError> {
 60 |         let payload = input.0;
 61 | 
 62 |         if payload.compilation_unit_index < 1
 63 |             || payload.compilation_unit_index > self.state.contexts.len()
 64 |         {
 65 |             return mcp_error!(
 66 |                 "Invalid compilation unit index: {}. Must be in range [1, {}]",
 67 |                 payload.compilation_unit_index,
 68 |                 self.state.contexts.len()
 69 |             );
 70 |         }
 71 | 
 72 |         let context = self
 73 |             .state
 74 |             .contexts
 75 |             .get(payload.compilation_unit_index - 1)
 76 |             .expect("Compilation unit index bounds check failed");
 77 | 
 78 |         let Some(ASTNode::ContractDefinition(contract)) = context.nodes.get(&payload.node_id)
 79 |         else {
 80 |             return mcp_error!(
 81 |                 "Node ID {} does not correspond to a contract definition",
 82 |                 payload.node_id
 83 |             );
 84 |         };
 85 | 
 86 |         let (filepath, _, _) = context.get_node_sort_key_from_capturable(&contract.into());
 87 |         let total_state_variables = get_total_state_variables(context, contract);
 88 |         let reversed_chain = get_inheritance_chain_info(context, contract)?;
 89 |         let entrypoints = get_classified_entrypoint_functions(context, contract)?;
 90 | 
 91 |         let contract_surface = ContractSurfaceBuilder::default()
 92 |             .name(contract.name.clone())
 93 |             .node_id(payload.node_id)
 94 |             .filepath(filepath)
 95 |             .compilation_unit_index(payload.compilation_unit_index)
 96 |             .total_state_variables(total_state_variables)
 97 |             .reversed_chain(reversed_chain)
 98 |             .entrypoints(entrypoints)
 99 |             .build()
100 |             .expect("failed to build contract surface");
101 | 
102 |         mcp_success!(contract_surface)
103 |     }
104 | }
105 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/abi_encode_packed_hash_collision.rs:
--------------------------------------------------------------------------------

```rust
 1 | use std::{collections::BTreeMap, error::Error};
 2 | 
 3 | use crate::{
 4 |     ast::NodeID,
 5 |     capture,
 6 |     context::workspace::WorkspaceContext,
 7 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 8 | };
 9 | use eyre::Result;
10 | 
11 | #[derive(Default)]
12 | pub struct AvoidAbiEncodePackedDetector {
13 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
14 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
15 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
16 | }
17 | 
18 | impl IssueDetector for AvoidAbiEncodePackedDetector {
19 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
20 |         for member_access in context.member_accesses() {
21 |             // If the member_access's member_name = "encodePacked", loop through the argument_types
22 |             // and count how many of them contain any of the following in type_strings:
23 |             // ["bytes ", "[]", "string"]
24 |             // If the count is greater than 1, add the member_access to the found_abi_encode_packed
25 |             // vector
26 |             if member_access.member_name == "encodePacked" {
27 |                 let mut count = 0;
28 |                 let argument_types = member_access.argument_types.as_ref().unwrap();
29 |                 for argument_type in argument_types {
30 |                     if argument_type.type_string.as_ref().unwrap().contains("bytes ")
31 |                         || argument_type.type_string.as_ref().unwrap().contains("[]")
32 |                         || argument_type.type_string.as_ref().unwrap().contains("string")
33 |                     {
34 |                         count += 1;
35 |                     }
36 |                 }
37 |                 if count > 1 {
38 |                     capture!(self, context, member_access);
39 |                 }
40 |             }
41 |         }
42 |         Ok(!self.found_instances.is_empty())
43 |     }
44 | 
45 |     fn title(&self) -> String {
46 |         String::from("`abi.encodePacked()` Hash Collision")
47 |     }
48 | 
49 |     fn description(&self) -> String {
50 |         String::from(
51 |             "abi.encodePacked() should not be used with dynamic types when passing the result to a hash function such as `keccak256()`. \
52 |         Use `abi.encode()` instead which will pad items to 32 bytes, preventing hash collisions: https://docs.soliditylang.org/en/v0.8.13/abi-spec.html#non-standard-packed-mode. \
53 |         (e.g. `abi.encodePacked(0x123,0x456)` => `0x123456` => `abi.encodePacked(0x1,0x23456)`, but `abi.encode(0x123,0x456)` => `0x0...1230...456`). \
54 |         Unless there is a compelling reason, `abi.encode` should be preferred. If there is only one argument to `abi.encodePacked()` \
55 |         it can often be cast to `bytes()` or `bytes32()` instead: https://ethereum.stackexchange.com/questions/30912/how-to-compare-strings-in-solidity#answer-82739. \
56 |         If all arguments are strings and or bytes, `bytes.concat()` should be used instead.",
57 |         )
58 |     }
59 | 
60 |     fn severity(&self) -> IssueSeverity {
61 |         IssueSeverity::High
62 |     }
63 | 
64 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
65 |         self.found_instances.clone()
66 |     }
67 | 
68 |     fn name(&self) -> String {
69 |         format!("{}", IssueDetectorNamePool::AbiEncodePackedHashCollision)
70 |     }
71 | }
72 | 
73 | #[cfg(test)]
74 | mod avoid_abi_encode_packed_tests {
75 | 
76 |     use crate::detect::detector::IssueDetector;
77 | 
78 |     use super::AvoidAbiEncodePackedDetector;
79 | 
80 |     #[test]
81 |     fn test_avoid_abi_encode_packed_detectorby_by_loading_contract_directly() {
82 |         let context = crate::detect::test_utils::load_solidity_source_unit(
83 |             "../tests/contract-playground/src/KeccakContract.sol",
84 |         );
85 | 
86 |         let mut detector = AvoidAbiEncodePackedDetector::default();
87 |         let found = detector.detect(&context).unwrap();
88 |         assert!(found);
89 |         assert_eq!(detector.instances().len(), 3);
90 |     }
91 | }
92 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/out_of_order_retryable.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, error::Error};
  2 | 
  3 | use crate::ast::{Expression, MemberAccess, NodeID};
  4 | 
  5 | use crate::{
  6 |     capture,
  7 |     context::{
  8 |         browser::ExtractFunctionCalls,
  9 |         graph::{CallGraphConsumer, CallGraphDirection, CallGraphVisitor},
 10 |         workspace::WorkspaceContext,
 11 |     },
 12 |     detect::{
 13 |         detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 14 |         helpers,
 15 |     },
 16 | };
 17 | use eyre::Result;
 18 | 
 19 | #[derive(Default)]
 20 | pub struct OutOfOrderRetryableDetector {
 21 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 22 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 23 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 24 | }
 25 | 
 26 | impl IssueDetector for OutOfOrderRetryableDetector {
 27 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 28 |         for func in helpers::get_implemented_external_and_public_functions(context) {
 29 |             let callgraphs =
 30 |                 CallGraphConsumer::get(context, &[&(func.into())], CallGraphDirection::Inward)?;
 31 |             for callgraph in callgraphs {
 32 |                 let mut tracker = OutOfOrderRetryableTracker { number_of_retry_calls: 0 };
 33 |                 callgraph.accept(context, &mut tracker)?;
 34 |                 if tracker.number_of_retry_calls >= 2 {
 35 |                     capture!(self, context, func);
 36 |                 }
 37 |             }
 38 |         }
 39 | 
 40 |         Ok(!self.found_instances.is_empty())
 41 |     }
 42 | 
 43 |     fn severity(&self) -> IssueSeverity {
 44 |         IssueSeverity::High
 45 |     }
 46 | 
 47 |     fn title(&self) -> String {
 48 |         String::from("Out of Order Retryable Transaction")
 49 |     }
 50 | 
 51 |     fn description(&self) -> String {
 52 |         String::from("Do not rely on the order or successful execution of retryable tickets. Functions like \
 53 |             createRetryableTicket, outboundTransferCustomRefund, unsafeCreateRetryableTicket are free to be re-tried in any
 54 |             order if they fail in the first go. Since this operation happens off chain, the sequencer is in control of the
 55 |             order of these transactions. Therefore, restrict the use to at most 1 ticket call per function.")
 56 |     }
 57 | 
 58 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 59 |         self.found_instances.clone()
 60 |     }
 61 | 
 62 |     fn name(&self) -> String {
 63 |         format!("{}", IssueDetectorNamePool::OutOfOrderRetryable)
 64 |     }
 65 | }
 66 | 
 67 | struct OutOfOrderRetryableTracker {
 68 |     number_of_retry_calls: usize,
 69 | }
 70 | 
 71 | const SEQUENCER_FUNCTIONS: [&str; 3] =
 72 |     ["createRetryableTicket", "outboundTransferCustomRefund", "unsafeCreateRetryableTicket"];
 73 | 
 74 | impl CallGraphVisitor for OutOfOrderRetryableTracker {
 75 |     fn visit_any(&mut self, node: &crate::ast::ASTNode) -> eyre::Result<()> {
 76 |         if self.number_of_retry_calls >= 2 {
 77 |             return Ok(());
 78 |         }
 79 |         let function_calls = ExtractFunctionCalls::from(node).extracted;
 80 |         for func_call in function_calls {
 81 |             if let Expression::MemberAccess(MemberAccess { member_name, .. }) =
 82 |                 func_call.expression.as_ref()
 83 |                 && SEQUENCER_FUNCTIONS.iter().any(|f| f == member_name)
 84 |             {
 85 |                 self.number_of_retry_calls += 1;
 86 |             }
 87 |         }
 88 |         Ok(())
 89 |     }
 90 | }
 91 | 
 92 | #[cfg(test)]
 93 | mod out_of_order_retryable_tests {
 94 | 
 95 |     use crate::detect::{
 96 |         detector::IssueDetector, high::out_of_order_retryable::OutOfOrderRetryableDetector,
 97 |     };
 98 | 
 99 |     #[test]
100 | 
101 |     fn test_out_of_order_retryable() {
102 |         let context = crate::detect::test_utils::load_solidity_source_unit(
103 |             "../tests/contract-playground/src/OutOfOrderRetryable.sol",
104 |         );
105 | 
106 |         let mut detector = OutOfOrderRetryableDetector::default();
107 |         let found = detector.detect(&context).unwrap();
108 |         assert!(found);
109 |         assert_eq!(detector.instances().len(), 2);
110 |     }
111 | }
112 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/unchecked_low_level_call.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, error::Error};
  2 | 
  3 | use crate::ast::{ASTNode, NodeID, NodeType};
  4 | 
  5 | use crate::{
  6 |     capture,
  7 |     context::{
  8 |         browser::{GetClosestAncestorOfTypeX, GetImmediateParent},
  9 |         workspace::WorkspaceContext,
 10 |     },
 11 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 12 | };
 13 | use eyre::Result;
 14 | 
 15 | #[derive(Default)]
 16 | pub struct UncheckedLowLevelCallDetector {
 17 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 18 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 19 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 20 | }
 21 | 
 22 | impl IssueDetector for UncheckedLowLevelCallDetector {
 23 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 24 |         let call_types = ["call", "staticcall", "delegatecall"];
 25 |         for member_access in context.member_accesses() {
 26 |             if call_types.iter().any(|&c| c == member_access.member_name)
 27 |                 && member_access.expression.type_descriptions().is_some_and(|type_desc| {
 28 |                     type_desc.type_string.as_ref().is_some_and(|type_string| {
 29 |                         type_string == "address" || type_string == "address payable"
 30 |                     })
 31 |                 })
 32 |                 && let Some(ASTNode::FunctionCall(func_call)) =
 33 |                     member_access.closest_ancestor_of_type(context, NodeType::FunctionCall)
 34 |             {
 35 |                 // In most cases, it's enough to check if the function call's parent is Block
 36 |                 // But to cover this case - dst.call.value(msg.value)("");
 37 |                 // We need to also check for the possibility where the function call's parent is
 38 |                 // another function call and that has a direct parent of type block
 39 |                 if let Some(ASTNode::ExpressionStatement(e)) = func_call.parent(context)
 40 |                     && e.parent(context).is_some_and(|node| node.node_type() == NodeType::Block)
 41 |                 {
 42 |                     capture!(self, context, func_call);
 43 |                 }
 44 | 
 45 |                 if let Some(ASTNode::FunctionCall(outside_parent)) = func_call.parent(context)
 46 |                     && let Some(ASTNode::ExpressionStatement(e)) = outside_parent.parent(context)
 47 |                     && e.parent(context).is_some_and(|node| node.node_type() == NodeType::Block)
 48 |                 {
 49 |                     capture!(self, context, func_call);
 50 |                 }
 51 |             }
 52 |         }
 53 | 
 54 |         Ok(!self.found_instances.is_empty())
 55 |     }
 56 | 
 57 |     fn severity(&self) -> IssueSeverity {
 58 |         IssueSeverity::High
 59 |     }
 60 | 
 61 |     fn title(&self) -> String {
 62 |         String::from("Unchecked Low level calls")
 63 |     }
 64 | 
 65 |     fn description(&self) -> String {
 66 |         String::from(
 67 |             "The return value of the low-level call is not checked, so if the call fails, the Ether will be locked in the contract. If the low level is used to prevent blocking operations, consider logging failed calls. Ensure that the return value of a low-level call is checked or logged.",
 68 |         )
 69 |     }
 70 | 
 71 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 72 |         self.found_instances.clone()
 73 |     }
 74 | 
 75 |     fn name(&self) -> String {
 76 |         format!("{}", IssueDetectorNamePool::UncheckedLowLevelCall)
 77 |     }
 78 | }
 79 | 
 80 | #[cfg(test)]
 81 | mod unchecked_low_level_calls_tests {
 82 | 
 83 |     use crate::detect::{
 84 |         detector::IssueDetector, high::unchecked_low_level_call::UncheckedLowLevelCallDetector,
 85 |     };
 86 | 
 87 |     #[test]
 88 | 
 89 |     fn test_unchecked_low_level_calls() {
 90 |         let context = crate::detect::test_utils::load_solidity_source_unit(
 91 |             "../tests/contract-playground/src/UncheckedCalls.sol",
 92 |         );
 93 | 
 94 |         let mut detector = UncheckedLowLevelCallDetector::default();
 95 |         let found = detector.detect(&context).unwrap();
 96 | 
 97 |         assert!(found);
 98 |         assert_eq!(detector.instances().len(), 9);
 99 |     }
100 | }
101 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/unused_public_function.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, error::Error};
  2 | 
  3 | use crate::{
  4 |     ast::{FunctionKind, NodeID, Visibility},
  5 |     capture,
  6 |     context::{
  7 |         browser::GetClosestAncestorOfTypeX,
  8 |         workspace::{ASTNode, WorkspaceContext},
  9 |     },
 10 |     detect::{
 11 |         detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 12 |         helpers::count_identifiers_that_reference_an_id,
 13 |     },
 14 | };
 15 | use eyre::Result;
 16 | 
 17 | #[derive(Default)]
 18 | pub struct UnusedPublicFunctionDetector {
 19 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 20 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 21 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 22 | }
 23 | 
 24 | impl IssueDetector for UnusedPublicFunctionDetector {
 25 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 26 |         let unreferenced_public_functions =
 27 |             context.function_definitions().into_iter().filter(|&function| {
 28 |                 matches!(function.visibility, Visibility::Public)
 29 |                     && !matches!(function.kind(), &FunctionKind::Constructor)
 30 |                     && function.overrides.is_none()
 31 |                     && !function.is_virtual
 32 |                     && count_identifiers_that_reference_an_id(context, function.id) == 0
 33 |             });
 34 | 
 35 |         for unreferenced_public_function in unreferenced_public_functions {
 36 |             if let Some(ASTNode::ContractDefinition(parent_contract)) = unreferenced_public_function
 37 |                 .closest_ancestor_of_type(context, crate::ast::NodeType::ContractDefinition)
 38 |                 && parent_contract.is_abstract
 39 |             {
 40 |                 continue;
 41 |             }
 42 |             capture!(self, context, unreferenced_public_function);
 43 |         }
 44 | 
 45 |         Ok(!self.found_instances.is_empty())
 46 |     }
 47 | 
 48 |     fn title(&self) -> String {
 49 |         String::from("Public Function Not Used Internally")
 50 |     }
 51 | 
 52 |     fn description(&self) -> String {
 53 |         String::from(
 54 |             "If a function is marked public but is not used internally, consider marking it as `external`.",
 55 |         )
 56 |     }
 57 | 
 58 |     fn severity(&self) -> IssueSeverity {
 59 |         IssueSeverity::Low
 60 |     }
 61 | 
 62 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 63 |         self.found_instances.clone()
 64 |     }
 65 | 
 66 |     fn name(&self) -> String {
 67 |         format!("{}", IssueDetectorNamePool::UnusedPublicFunction)
 68 |     }
 69 | }
 70 | 
 71 | #[cfg(test)]
 72 | mod useless_public_function_tests {
 73 |     use crate::detect::detector::IssueDetector;
 74 | 
 75 |     use super::UnusedPublicFunctionDetector;
 76 | 
 77 |     #[test]
 78 | 
 79 |     fn test_useless_public_functions_by_loading_contract_directly() {
 80 |         let context = crate::detect::test_utils::load_solidity_source_unit(
 81 |             "../tests/contract-playground/src/Counter.sol",
 82 |         );
 83 | 
 84 |         let mut detector = UnusedPublicFunctionDetector::default();
 85 |         let found = detector.detect(&context).unwrap();
 86 |         assert!(found);
 87 |         assert_eq!(detector.instances().len(), 1);
 88 |     }
 89 | 
 90 |     #[test]
 91 | 
 92 |     fn test_useless_public_functions_does_not_capture_abstract_contract_functions() {
 93 |         let context = crate::detect::test_utils::load_solidity_source_unit(
 94 |             "../tests/contract-playground/src/AbstractContract.sol",
 95 |         );
 96 | 
 97 |         let mut detector = UnusedPublicFunctionDetector::default();
 98 |         let found = detector.detect(&context).unwrap();
 99 |         assert!(!found);
100 |         assert_eq!(detector.instances().len(), 0);
101 |     }
102 | 
103 |     #[test]
104 | 
105 |     fn test_useless_public_functions_does_not_capture_virtual_or_overriding_functions() {
106 |         let context = crate::detect::test_utils::load_solidity_source_unit(
107 |             "../tests/contract-playground/src/PublicFunction.sol",
108 |         );
109 | 
110 |         let mut detector = UnusedPublicFunctionDetector::default();
111 |         let found = detector.detect(&context).unwrap();
112 |         assert!(!found);
113 |         assert_eq!(detector.instances().len(), 0);
114 |     }
115 | }
116 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high.rs:
--------------------------------------------------------------------------------

```rust
 1 | pub(crate) mod abi_encode_packed_hash_collision;
 2 | pub(crate) mod arbitrary_transfer_from;
 3 | pub(crate) mod const_func_changes_state;
 4 | pub(crate) mod contract_locks_ether;
 5 | pub(crate) mod dangerous_unary_operator;
 6 | pub(crate) mod delegate_call_unchecked_address;
 7 | pub(crate) mod delete_nested_mapping;
 8 | pub(crate) mod dynamic_array_length_assignment;
 9 | pub(crate) mod enumerable_loop_removal;
10 | pub(crate) mod eth_send_unchecked_address;
11 | pub(crate) mod experimental_encoder;
12 | pub(crate) mod function_selector_collision;
13 | pub(crate) mod incorrect_caret_operator;
14 | pub(crate) mod incorrect_erc20_interface;
15 | pub(crate) mod incorrect_erc721_interface;
16 | pub(crate) mod incorrect_shift_order;
17 | pub(crate) mod misused_boolean;
18 | pub(crate) mod msg_value_in_loops;
19 | pub(crate) mod multiple_constructors;
20 | pub(crate) mod nested_struct_in_mapping;
21 | pub(crate) mod out_of_order_retryable;
22 | pub(crate) mod pre_declared_variable_usage;
23 | pub(crate) mod reentrancy_state_change;
24 | pub(crate) mod reused_contract_name;
25 | pub(crate) mod rtlo;
26 | pub(crate) mod selfdestruct;
27 | pub(crate) mod signed_integer_storage_array;
28 | pub(crate) mod state_variable_shadowing;
29 | pub(crate) mod storage_array_memory_edit;
30 | pub(crate) mod strict_equality_contract_balance;
31 | pub(crate) mod tautological_compare;
32 | pub(crate) mod tautology_or_contradiction;
33 | pub(crate) mod tx_origin_used_for_auth;
34 | pub(crate) mod unchecked_low_level_call;
35 | pub(crate) mod unchecked_send;
36 | pub(crate) mod unprotected_initializer;
37 | pub(crate) mod unsafe_casting;
38 | pub(crate) mod weak_randomness;
39 | pub(crate) mod yul_return;
40 | 
41 | pub use abi_encode_packed_hash_collision::AvoidAbiEncodePackedDetector;
42 | pub use arbitrary_transfer_from::ArbitraryTransferFromDetector;
43 | pub use const_func_changes_state::ConstantFunctionChangesStateDetector;
44 | pub use contract_locks_ether::ContractLocksEtherDetector;
45 | pub use dangerous_unary_operator::DangerousUnaryOperatorDetector;
46 | pub use delegate_call_unchecked_address::DelegateCallUncheckedAddressDetector;
47 | pub use delete_nested_mapping::DeletionNestedMappingDetector;
48 | pub use dynamic_array_length_assignment::DynamicArrayLengthAssignmentDetector;
49 | pub use enumerable_loop_removal::EnumerableLoopRemovalDetector;
50 | pub use eth_send_unchecked_address::SendEtherNoChecksDetector;
51 | pub use experimental_encoder::ExperimentalEncoderDetector;
52 | pub use function_selector_collision::FunctionSelectorCollisionDetector;
53 | pub use incorrect_caret_operator::IncorrectUseOfCaretOperatorDetector;
54 | pub use incorrect_erc20_interface::IncorrectERC20InterfaceDetector;
55 | pub use incorrect_erc721_interface::IncorrectERC721InterfaceDetector;
56 | pub use incorrect_shift_order::IncorrectShiftOrderDetector;
57 | pub use misused_boolean::MisusedBooleanDetector;
58 | pub use msg_value_in_loops::MsgValueUsedInLoopDetector;
59 | pub use multiple_constructors::MultipleConstructorsDetector;
60 | pub use nested_struct_in_mapping::NestedStructInMappingDetector;
61 | pub use out_of_order_retryable::OutOfOrderRetryableDetector;
62 | pub use pre_declared_variable_usage::PreDeclaredLocalVariableUsageDetector;
63 | pub use reentrancy_state_change::ReentrancyStateChangeDetector;
64 | pub use reused_contract_name::ReusedContractNameDetector;
65 | pub use rtlo::RTLODetector;
66 | pub use selfdestruct::SelfdestructDetector;
67 | pub use signed_integer_storage_array::StorageSignedIntegerArrayDetector;
68 | pub use state_variable_shadowing::StateVariableShadowingDetector;
69 | pub use storage_array_memory_edit::StorageArrayMemoryEditDetector;
70 | pub use strict_equality_contract_balance::DangerousStrictEqualityOnBalanceDetector;
71 | pub use tautological_compare::TautologicalCompareDetector;
72 | pub use tautology_or_contradiction::TautologyOrContraditionDetector;
73 | pub use tx_origin_used_for_auth::TxOriginUsedForAuthDetector;
74 | pub use unchecked_low_level_call::UncheckedLowLevelCallDetector;
75 | pub use unchecked_send::UncheckedSendDetector;
76 | pub use unprotected_initializer::UnprotectedInitializerDetector;
77 | pub use unsafe_casting::UnsafeCastingDetector;
78 | pub use weak_randomness::WeakRandomnessDetector;
79 | pub use yul_return::YulReturnDetector;
80 | 
```

--------------------------------------------------------------------------------
/aderyn_driver/src/process.rs:
--------------------------------------------------------------------------------

```rust
  1 | use crate::{
  2 |     compile,
  3 |     config::supplement_values_from_aderyn_toml,
  4 |     driver::{CliArgsCommonConfig, CliArgsInputConfig},
  5 | };
  6 | use aderyn_core::{
  7 |     context::{
  8 |         graph::{LegacyWorkspaceCallGraph, Transpose, WorkspaceCallGraphs},
  9 |         router::Router,
 10 |         workspace::WorkspaceContext,
 11 |     },
 12 |     stats,
 13 | };
 14 | use solidity_ast::ProjectConfigInput;
 15 | use std::{
 16 |     collections::HashMap,
 17 |     path::{Path, PathBuf},
 18 | };
 19 | 
 20 | pub struct WorkspaceContextWrapper {
 21 |     pub contexts: Vec<WorkspaceContext>,
 22 |     pub root_path: PathBuf,
 23 |     pub project_config: ProjectConfigInput,
 24 | }
 25 | 
 26 | pub struct PreprocessedConfig {
 27 |     pub root_path: PathBuf,
 28 |     pub src: Option<String>,
 29 |     pub include: Option<Vec<String>>,
 30 |     pub exclude: Option<Vec<String>>,
 31 | }
 32 | 
 33 | pub fn make_context(
 34 |     args: &CliArgsInputConfig,
 35 |     common: &CliArgsCommonConfig,
 36 | ) -> Result<WorkspaceContextWrapper, Box<dyn std::error::Error + Send + Sync>> {
 37 |     // Preprocess config by supplementing CLI args with aderyn.toml if exists
 38 |     let preprocessed_config = obtain_config_values(args.clone())?;
 39 | 
 40 |     let root_path = preprocessed_config.root_path.clone();
 41 | 
 42 |     // Compilation steps:
 43 |     // 1. Processes the above preprocessed config by translating them to runtime values Thanks to
 44 |     //    Cyfrin/solidity-ast-rs
 45 |     // 2. Parse those files and prepare ASTs.
 46 |     let (mut contexts, project_config) =
 47 |         compile::compile_project(preprocessed_config, common.lsp, common.verbose)?;
 48 | 
 49 |     // Only make this an error when it's not in LSP mode
 50 |     if !common.lsp && contexts.iter().all(|c| c.src_filepaths.is_empty()) {
 51 |         let error = "No solidity files found in given scope!";
 52 |         eprintln!("{}", error);
 53 |         return Err(error.into());
 54 |     }
 55 | 
 56 |     // Supplement the context
 57 |     // 1. Inject nSLOC stats
 58 |     // 2. Collect lines marked by aderyn-ignore-line, aderyn-ignore-next-line
 59 |     // 3. Inject Legacy Callgraph
 60 |     // 4. Inject Router
 61 |     // 5. Inject New Callgraph
 62 |     for context in contexts.iter_mut() {
 63 |         let absolute_root_path = &ensure_valid_root_path(&root_path);
 64 |         let stats = stats::collect_stats(absolute_root_path.as_path(), common.skip_cloc, context);
 65 |         let sloc_stats: HashMap<String, usize> =
 66 |             stats.iter().map(|(key, value)| (key.to_owned(), value.code)).collect();
 67 | 
 68 |         let ignore_line_stats: HashMap<String, Vec<stats::IgnoreLine>> =
 69 |             stats.iter().map(|(key, value)| (key.to_owned(), value.ignore_lines.clone())).collect();
 70 | 
 71 |         context.set_sloc_stats(sloc_stats);
 72 |         context.set_ignore_lines_stats(ignore_line_stats);
 73 | 
 74 |         let inward_callgraph = LegacyWorkspaceCallGraph::from_context(context)?;
 75 |         let outward_callgraph =
 76 |             LegacyWorkspaceCallGraph { raw_callgraph: inward_callgraph.raw_callgraph.reverse() };
 77 |         context.inward_callgraph = Some(inward_callgraph);
 78 |         context.outward_callgraph = Some(outward_callgraph);
 79 | 
 80 |         let router = Router::build(context);
 81 |         context.router = Some(router);
 82 | 
 83 |         let callgraphs = WorkspaceCallGraphs::build(context);
 84 |         context.callgraphs = Some(callgraphs);
 85 |     }
 86 | 
 87 |     Ok(WorkspaceContextWrapper { contexts, root_path, project_config })
 88 | }
 89 | 
 90 | /// Supplement the CLI arguments with values from aderyn.toml
 91 | fn obtain_config_values(
 92 |     args: CliArgsInputConfig,
 93 | ) -> Result<PreprocessedConfig, Box<dyn std::error::Error + Send + Sync>> {
 94 |     let root_path = PathBuf::from(&args.root);
 95 |     let aderyn_path = root_path.join("aderyn.toml");
 96 | 
 97 |     let current = PreprocessedConfig {
 98 |         root_path,
 99 |         src: args.src,
100 |         exclude: args.path_excludes,
101 |         include: args.path_includes,
102 |     };
103 | 
104 |     // Process aderyn.toml if it exists
105 |     if aderyn_path.exists() {
106 |         return supplement_values_from_aderyn_toml(current);
107 |     }
108 |     Ok(current)
109 | }
110 | 
111 | fn ensure_valid_root_path(root_path: &Path) -> PathBuf {
112 |     if !root_path.exists() {
113 |         eprintln!("{} does not exist!", root_path.to_string_lossy());
114 |         std::process::exit(1);
115 |     }
116 |     std::fs::canonicalize(root_path).unwrap()
117 | }
118 | 
```

--------------------------------------------------------------------------------
/aderyn_core/templates/mcp-tool-response/contract_surface.md:
--------------------------------------------------------------------------------

```markdown
  1 | ## Contract Surface Inspector for {{ name }}
  2 | 
  3 | *Contract name:* {{ name }}
  4 | 
  5 | *Contract ID:* {{ node_id }}
  6 | 
  7 | *Compilation Unit index:* {{ compilation_unit_index }}
  8 | 
  9 | *Filepath:* {{ filepath }}
 10 | 
 11 | ### C3 Linearized Inheritance
 12 | 
 13 | After performing C3 linearization on the main contract {{ name }}, the following chain is the end result. It goes from the most base parent class at the beginning to the most derived class at the end of the list chain.
 14 | 
 15 | The last contract class in the chain is {{ name }} because it is the most derived contract class in its hierarchy.
 16 | 
 17 | List of names of contract class in the inheritance chain of {{ name }} along with their filepath.
 18 | 
 19 | **Total contracts in inheritance chain:** {{ reversed_chain.len() }}
 20 | 
 21 | {% for c in reversed_chain %}
 22 | {{ loop.index }}. {{ c.name }} | Node ID: {{ c.node_id }} | Filepath: {{ c.filepath }}
 23 | {% endfor %}
 24 | 
 25 | ### State variables
 26 | 
 27 | State variables of a contract include all variables defined in the contract itself plus those inherited from parent classes.
 28 | 
 29 | {% if total_state_variables == 0 %}
 30 | *No state variables found*
 31 | {% else %}
 32 | The following code snippets show all state variables defined in each contract class within the inheritance chain.
 33 | 
 34 | {% for c in reversed_chain %}
 35 | {{ loop.index }}. {{ c.name }}
 36 | 
 37 | {% if c.state_variables.len() == 0 %}
 38 | No state variables found defined in {{ c.name }}
 39 | {% else %}
 40 | ```solidity
 41 | {% for s in c.state_variables %}
 42 | {{ s }}
 43 | {% endfor %}
 44 | ```
 45 | {% endif %}
 46 | 
 47 | {% endfor %}
 48 | 
 49 | {% endif %}
 50 | 
 51 | ### Entrypoint functions
 52 | 
 53 | In Solidity, entrypoint functions are functions that can be called from outside the contract or serve as initial execution points. The main types of entrypoint functions are external functions, public functions, fallback functions, and receive functions.
 54 | 
 55 | The following is a list of entrypoint functions for {{ name }} with their corresponding Node IDs and the contract class in the inheritance chain where each function is defined.
 56 | 
 57 | If a function has been overridden, it won't be listed in here. This list contains all the functions after filtering out the ones that are actually called.
 58 | 
 59 | #### External Functions
 60 | 
 61 | {% if entrypoints.external_functions.len() == 0 %}
 62 | *No external functions found*
 63 | {% else %}
 64 | {% for func in entrypoints.external_functions %}
 65 | {{ loop.index }}. **{{ func.name }}** | Function's Node Id: {{ func.node_id }} | Containing contract class: {{ func.containing_contract.name }} | Containing contract's Node Id: {{ func.containing_contract.node_id }}
 66 | {% endfor %}
 67 | {% endif %}
 68 | 
 69 | #### Public Functions
 70 | 
 71 | {% if entrypoints.public_functions.len() == 0 %}
 72 | *No public functions found*
 73 | {% else %}
 74 | {% for func in entrypoints.public_functions %}
 75 | {{ loop.index }}. **{{ func.name }}** | Function's Node Id: {{ func.node_id }} | Containing contract class: {{ func.containing_contract.name }} | Containing contract's Node Id: {{ func.containing_contract.node_id }}
 76 | {% endfor %}
 77 | {% endif %}
 78 | 
 79 | #### Fallback Function
 80 | 
 81 | {% if let Some(fallback_function) = entrypoints.fallback_function %}
 82 | Node Id: {{ fallback_function.node_id }} | Containing contract class: {{ fallback_function.containing_contract.name }} | Containing contract's Node Id: {{ fallback_function.containing_contract.node_id }}
 83 | {% else %}
 84 | *No fallback function found.*
 85 | {% endif %}
 86 | 
 87 | #### Receive Function
 88 | 
 89 | {% if let Some(receive_function) = entrypoints.receive_function %}
 90 | Node Id: {{ receive_function.node_id }} | Containing contract class: {{ receive_function.containing_contract.name }} | Containing contract's Node Id: {{ receive_function.containing_contract.node_id }}
 91 | {% else %}
 92 | *No receive function found.*
 93 | {% endif %}
 94 | 
 95 | ### Suggestion for next steps:
 96 | 
 97 | Try to explore callgraphs starting from a given entrypoint function. To do that, use the callgraph provider tool and pass the entrypoint function's Node ID, and the Node ID of the original deployable contract (same one used to call this contract surface tool). NOT just the containing contract's Node ID.
 98 | 
 99 | A good analysis explores the project on a per callgraph basis for entrypoints of interest. This provides a holistic picture and therefore less false positives.
100 | 
```

--------------------------------------------------------------------------------
/benchmarks/report/index.html:
--------------------------------------------------------------------------------

```html
  1 | <!DOCTYPE html>
  2 | <html>
  3 | 
  4 | <head>
  5 |     <meta http-equiv="Content-Type" content="text/html; charset=utf-8">
  6 |     <title>Index - Criterion.rs</title>
  7 |     <style type="text/css">
  8 |         body {
  9 |             font: 14px Helvetica Neue;
 10 |             text-rendering: optimizelegibility;
 11 |         }
 12 | 
 13 |         .body {
 14 |             width: 960px;
 15 |             margin: auto;
 16 |         }
 17 | 
 18 |         a:link {
 19 |             color: #1F78B4;
 20 |             text-decoration: none;
 21 |         }
 22 | 
 23 |         h2 {
 24 |             font-size: 36px;
 25 |             font-weight: 300;
 26 |         }
 27 | 
 28 |         h3 {
 29 |             font-size: 24px;
 30 |             font-weight: 300;
 31 |         }
 32 | 
 33 |         #footer {
 34 |             height: 40px;
 35 |             background: #888;
 36 |             color: white;
 37 |             font-size: larger;
 38 |             font-weight: 300;
 39 |         }
 40 | 
 41 |         #footer a {
 42 |             color: white;
 43 |             text-decoration: underline;
 44 |         }
 45 | 
 46 |         #footer p {
 47 |             text-align: center
 48 |         }
 49 | 
 50 |         table {
 51 |             border-collapse: collapse;
 52 |         }
 53 | 
 54 |         table,
 55 |         th,
 56 |         td {
 57 |             border: 1px solid #888;
 58 |         }
 59 |     </style>
 60 | </head>
 61 | 
 62 | <body>
 63 |     <div class="body">
 64 |         <h2>Criterion.rs Benchmark Index</h2>
 65 |         See individual benchmark pages below for more details.
 66 |         <ul>
 67 |             <li><a href="../aderyn/report/index.html">aderyn</a></li>
 68 |             <li><a href="../arbitrary-transfer-from/report/index.html">arbitrary-transfer-from</a></li>
 69 |             <li><a href="../avoid-abi-encode-packed/report/index.html">avoid-abi-encode-packed</a></li>
 70 |             <li><a href="../block-timestamp-deadline/report/index.html">block-timestamp-deadline</a></li>
 71 |             <li><a href="../centralization-risk/report/index.html">centralization-risk</a></li>
 72 |             <li><a href="../constants-instead-of-literals/report/index.html">constants-instead-of-literals</a></li>
 73 |             <li><a href="../delegate-call-in-loop/report/index.html">delegate-call-in-loop</a></li>
 74 |             <li><a href="../deprecated-oz-functions/report/index.html">deprecated-oz-functions</a></li>
 75 |             <li><a href="../ecrecover/report/index.html">ecrecover</a></li>
 76 |             <li><a href="../empty-block/report/index.html">empty-block</a></li>
 77 |             <li><a href="../hello_world/report/index.html">hello_world</a></li>
 78 |             <li><a href="../inconsistent-type-names/report/index.html">inconsistent-type-names</a></li>
 79 |             <li><a href="../large-numeric-literal/report/index.html">large-numeric-literal</a></li>
 80 |             <li><a href="../non-reentrant-before-others/report/index.html">non-reentrant-before-others</a></li>
 81 |             <li><a href="../push-zero-opcode/report/index.html">push-zero-opcode</a></li>
 82 |             <li><a href="../require-with-string/report/index.html">require-with-string</a></li>
 83 |             <li><a href="../solmate-safe-transfer-lib/report/index.html">solmate-safe-transfer-lib</a></li>
 84 |             <li><a href="../unindexed-events/report/index.html">unindexed-events</a></li>
 85 |             <li><a href="../unprotected-initializer/report/index.html">unprotected-initializer</a></li>
 86 |             <li><a href="../unsafe-erc20-functions/report/index.html">unsafe-erc20-functions</a></li>
 87 |             <li><a href="../unsafe-oz-erc721-mint/report/index.html">unsafe-oz-erc721-mint</a></li>
 88 |             <li><a href="../unspecific-solidity-pragma/report/index.html">unspecific-solidity-pragma</a></li>
 89 |             <li><a href="../useless-internal-function/report/index.html">useless-internal-function</a></li>
 90 |             <li><a href="../useless-modifier/report/index.html">useless-modifier</a></li>
 91 |             <li><a href="../useless-public-function/report/index.html">useless-public-function</a></li>
 92 |             <li><a href="../zero-address-check/report/index.html">zero-address-check</a></li>
 93 |         </ul>
 94 |     </div>
 95 |     <div id="footer">
 96 |         <p>This report was generated by
 97 |             <a href="https://github.com/bheisler/criterion.rs">Criterion.rs</a>, a statistics-driven benchmarking
 98 |             library in Rust.</p>
 99 |     </div>
100 | </body>
101 | </html>
```

--------------------------------------------------------------------------------
/aderyn_core/src/context/mcp/contract_surface/util.rs:
--------------------------------------------------------------------------------

```rust
  1 | use super::render::*;
  2 | use crate::{
  3 |     ast::{ASTNode, ContractDefinition, FunctionKind, NodeType, Visibility},
  4 |     context::{
  5 |         browser::{ExtractVariableDeclarations, GetClosestAncestorOfTypeX},
  6 |         workspace::WorkspaceContext,
  7 |     },
  8 | };
  9 | use rmcp::ErrorData as McpError;
 10 | 
 11 | pub fn get_total_state_variables(
 12 |     context: &WorkspaceContext,
 13 |     original_contract: &ContractDefinition,
 14 | ) -> usize {
 15 |     let Some(state_vars) =
 16 |         original_contract.get_all_state_variables_in_linearized_base_contracts_chain(context)
 17 |     else {
 18 |         return 0;
 19 |     };
 20 |     state_vars.len()
 21 | }
 22 | 
 23 | pub fn get_classified_entrypoint_functions(
 24 |     context: &WorkspaceContext,
 25 |     original_contract: &ContractDefinition,
 26 | ) -> Result<EntrypointFunctions, McpError> {
 27 |     let Some(functions) = context.entrypoint_functions(original_contract) else {
 28 |         // TODO: investigate when you hit this case, it has been a while since I made the router
 29 |         return Ok(EntrypointFunctions::default());
 30 |     };
 31 |     let mut public_functions_info = vec![];
 32 |     let mut external_functions_info = vec![];
 33 |     let mut receive_function_info = None;
 34 |     let mut fallback_function_info = None;
 35 |     for func in functions {
 36 |         let Some(ASTNode::ContractDefinition(container)) =
 37 |             func.closest_ancestor_of_type(context, NodeType::ContractDefinition)
 38 |         else {
 39 |             continue;
 40 |         };
 41 |         let container = ContainingContractBuilder::default()
 42 |             .name(container.name.clone())
 43 |             .node_id(container.id)
 44 |             .build()
 45 |             .expect("failed to build container");
 46 | 
 47 |         let function_info = FunctionInfoBuilder::default()
 48 |             .name(func.name.clone())
 49 |             .node_id(func.id)
 50 |             .containing_contract(container)
 51 |             .build()
 52 |             .expect("failed to build function info");
 53 | 
 54 |         match *func.kind() {
 55 |             FunctionKind::Function => match func.visibility {
 56 |                 Visibility::Public => {
 57 |                     public_functions_info.push(function_info);
 58 |                 }
 59 |                 Visibility::External => {
 60 |                     external_functions_info.push(function_info);
 61 |                 }
 62 |                 Visibility::Internal | Visibility::Private => {} // not an entrypoint
 63 |             },
 64 |             FunctionKind::Receive => {
 65 |                 receive_function_info = Some(function_info);
 66 |             }
 67 |             FunctionKind::Fallback => {
 68 |                 fallback_function_info = Some(function_info);
 69 |             }
 70 |             FunctionKind::Constructor => {} // For now, constructor is not an entrypoint
 71 |             FunctionKind::FreeFunction => unreachable!(), // Free function is never an entrypoint
 72 |         };
 73 |     }
 74 | 
 75 |     let entrypoints = EntrypointFunctionsBuilder::default()
 76 |         .external_functions(external_functions_info)
 77 |         .public_functions(public_functions_info)
 78 |         .fallback_function(fallback_function_info)
 79 |         .receive_function(receive_function_info)
 80 |         .build()
 81 |         .expect("failed to build entrypoints in inheritance chain");
 82 |     Ok(entrypoints)
 83 | }
 84 | 
 85 | pub fn get_inheritance_chain_info(
 86 |     context: &WorkspaceContext,
 87 |     original_contract: &ContractDefinition,
 88 | ) -> Result<Vec<ContractInfo>, McpError> {
 89 |     let mut reversed_chain = vec![];
 90 |     for contract in original_contract.c3(context).collect::<Vec<_>>().into_iter().rev() {
 91 |         let variables = ExtractVariableDeclarations::from(contract).extracted;
 92 |         let state_variables = variables
 93 |             .iter()
 94 |             .filter(|v| v.state_variable)
 95 |             .map(|v| v.name.clone())
 96 |             .collect::<Vec<_>>();
 97 |         let (filepath, _, _) = context.get_node_sort_key_from_capturable(&contract.into());
 98 | 
 99 |         let contract_info = ContractInfoBuilder::default()
100 |             .name(contract.name.clone())
101 |             .node_id(contract.id)
102 |             .state_variables(state_variables)
103 |             .filepath(filepath)
104 |             .build()
105 |             .expect("failed to build contract info in inheritance chain");
106 |         reversed_chain.push(contract_info);
107 |     }
108 |     Ok(reversed_chain)
109 | }
110 | 
```

--------------------------------------------------------------------------------
/tests/ast/override.json:
--------------------------------------------------------------------------------

```json
1 | {"absolutePath":"a","exportedSymbols":{"A":[5],"B":[16],"C":[29]},"id":30,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"A","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":5,"linearizedBaseContracts":[5],"name":"A","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":3,"nodeType":"Block","src":"44:2:1","statements":[]},"functionSelector":"a399b6a2","id":4,"implemented":true,"kind":"function","modifiers":[],"name":"faa","nameLocation":"23:3:1","nodeType":"FunctionDefinition","parameters":{"id":1,"nodeType":"ParameterList","parameters":[],"src":"26:2:1"},"returnParameters":{"id":2,"nodeType":"ParameterList","parameters":[],"src":"44:0:1"},"scope":5,"src":"14:32:1","stateMutability":"nonpayable","virtual":true,"visibility":"public"}],"scope":30,"src":"0:48:1","usedErrors":[]},{"abstract":true,"baseContracts":[{"baseName":{"id":6,"name":"A","nameLocations":["72:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":5,"src":"72:1:1"},"id":7,"nodeType":"InheritanceSpecifier","src":"72:1:1"}],"canonicalName":"B","contractDependencies":[],"contractKind":"contract","fullyImplemented":false,"id":16,"linearizedBaseContracts":[16,5],"name":"B","nameLocation":"67:1:1","nodeType":"ContractDefinition","nodes":[{"functionSelector":"c2985578","id":10,"implemented":false,"kind":"function","modifiers":[],"name":"foo","nameLocation":"86:3:1","nodeType":"FunctionDefinition","parameters":{"id":8,"nodeType":"ParameterList","parameters":[],"src":"89:2:1"},"returnParameters":{"id":9,"nodeType":"ParameterList","parameters":[],"src":"106:0:1"},"scope":16,"src":"77:30:1","stateMutability":"nonpayable","virtual":true,"visibility":"public"},{"baseFunctions":[4],"body":{"id":14,"nodeType":"Block","src":"148:2:1","statements":[]},"functionSelector":"a399b6a2","id":15,"implemented":true,"kind":"function","modifiers":[],"name":"faa","nameLocation":"118:3:1","nodeType":"FunctionDefinition","overrides":{"id":12,"nodeType":"OverrideSpecifier","overrides":[],"src":"139:8:1"},"parameters":{"id":11,"nodeType":"ParameterList","parameters":[],"src":"121:2:1"},"returnParameters":{"id":13,"nodeType":"ParameterList","parameters":[],"src":"148:0:1"},"scope":16,"src":"109:41:1","stateMutability":"nonpayable","virtual":true,"visibility":"public"}],"scope":30,"src":"49:103:1","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":17,"name":"B","nameLocations":["167:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":16,"src":"167:1:1"},"id":18,"nodeType":"InheritanceSpecifier","src":"167:1:1"}],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":29,"linearizedBaseContracts":[29,16,5],"name":"C","nameLocation":"162:1:1","nodeType":"ContractDefinition","nodes":[{"baseFunctions":[10],"body":{"id":22,"nodeType":"Block","src":"203:3:1","statements":[]},"functionSelector":"c2985578","id":23,"implemented":true,"kind":"function","modifiers":[],"name":"foo","nameLocation":"181:3:1","nodeType":"FunctionDefinition","overrides":{"id":20,"nodeType":"OverrideSpecifier","overrides":[],"src":"194:8:1"},"parameters":{"id":19,"nodeType":"ParameterList","parameters":[],"src":"184:2:1"},"returnParameters":{"id":21,"nodeType":"ParameterList","parameters":[],"src":"203:0:1"},"scope":29,"src":"172:34:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"},{"baseFunctions":[15],"body":{"id":27,"nodeType":"Block","src":"239:3:1","statements":[]},"functionSelector":"a399b6a2","id":28,"implemented":true,"kind":"function","modifiers":[],"name":"faa","nameLocation":"217:3:1","nodeType":"FunctionDefinition","overrides":{"id":25,"nodeType":"OverrideSpecifier","overrides":[],"src":"230:8:1"},"parameters":{"id":24,"nodeType":"ParameterList","parameters":[],"src":"220:2:1"},"returnParameters":{"id":26,"nodeType":"ParameterList","parameters":[],"src":"239:0:1"},"scope":29,"src":"208:34:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":30,"src":"153:91:1","usedErrors":[]}],"src":"0:245:1"}
2 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/costly_loop.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, convert::identity, error::Error};
  2 | 
  3 | use crate::ast::{ASTNode, NodeID};
  4 | 
  5 | use crate::{capture, context::browser::ApproximateStorageChangeFinder};
  6 | 
  7 | use crate::{
  8 |     context::{
  9 |         graph::{CallGraphConsumer, CallGraphDirection, CallGraphVisitor},
 10 |         workspace::WorkspaceContext,
 11 |     },
 12 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 13 | };
 14 | use eyre::Result;
 15 | 
 16 | #[derive(Default)]
 17 | pub struct CostlyLoopDetector {
 18 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 19 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 20 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 21 | }
 22 | 
 23 | impl IssueDetector for CostlyLoopDetector {
 24 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 25 |         // Investigate for loops to check for storage writes
 26 |         for for_statement in context.for_statements() {
 27 |             if changes_state(context, &(for_statement.into())).is_some_and(identity) {
 28 |                 capture!(self, context, for_statement);
 29 |             }
 30 |         }
 31 | 
 32 |         // Investigate while loops to check for storage writes
 33 |         for while_statement in context.while_statements() {
 34 |             if changes_state(context, &(while_statement.into())).is_some_and(identity) {
 35 |                 capture!(self, context, while_statement);
 36 |             }
 37 |         }
 38 | 
 39 |         // Investigate the do while loops to check for storage writes
 40 |         for do_while_statement in context.do_while_statements() {
 41 |             if changes_state(context, &(do_while_statement.into())).is_some_and(identity) {
 42 |                 capture!(self, context, do_while_statement);
 43 |             }
 44 |         }
 45 | 
 46 |         Ok(!self.found_instances.is_empty())
 47 |     }
 48 | 
 49 |     fn severity(&self) -> IssueSeverity {
 50 |         IssueSeverity::Low
 51 |     }
 52 | 
 53 |     fn title(&self) -> String {
 54 |         String::from("Costly operations inside loop")
 55 |     }
 56 | 
 57 |     fn description(&self) -> String {
 58 |         String::from(
 59 |             "Invoking `SSTORE` operations in loops may waste gas. Use a local variable to hold the loop computation result.",
 60 |         )
 61 |     }
 62 | 
 63 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 64 |         self.found_instances.clone()
 65 |     }
 66 | 
 67 |     fn name(&self) -> String {
 68 |         IssueDetectorNamePool::CostlyLoop.to_string()
 69 |     }
 70 | }
 71 | 
 72 | fn changes_state(context: &WorkspaceContext, ast_node: &ASTNode) -> Option<bool> {
 73 |     // Now, investigate the function to see if there is scope for any state variable changes
 74 |     let callgraphs =
 75 |         CallGraphConsumer::get(context, &[ast_node], CallGraphDirection::Inward).ok()?;
 76 | 
 77 |     for callgraph in callgraphs {
 78 |         let mut tracker = StateVariableChangeTracker { state_var_has_changed: false, context };
 79 |         callgraph.accept(context, &mut tracker).ok()?;
 80 |         if tracker.state_var_has_changed {
 81 |             return Some(true);
 82 |         }
 83 |     }
 84 |     Some(false)
 85 | }
 86 | 
 87 | struct StateVariableChangeTracker<'a> {
 88 |     state_var_has_changed: bool,
 89 |     context: &'a WorkspaceContext,
 90 | }
 91 | 
 92 | impl CallGraphVisitor for StateVariableChangeTracker<'_> {
 93 |     fn visit_any(&mut self, node: &crate::ast::ASTNode) -> eyre::Result<()> {
 94 |         if self.state_var_has_changed {
 95 |             return Ok(());
 96 |         }
 97 |         // Check for state variable changes
 98 |         let finder = ApproximateStorageChangeFinder::from(self.context, node);
 99 |         if finder.state_variables_have_been_manipulated() {
100 |             self.state_var_has_changed = true;
101 |         }
102 |         Ok(())
103 |     }
104 | }
105 | 
106 | #[cfg(test)]
107 | mod costly_operations_inside_loops_tests {
108 | 
109 |     use crate::detect::{detector::IssueDetector, low::costly_loop::CostlyLoopDetector};
110 | 
111 |     #[test]
112 | 
113 |     fn test_costly_operations_inside_loops() {
114 |         let context = crate::detect::test_utils::load_solidity_source_unit(
115 |             "../tests/contract-playground/src/CostlyOperationsInsideLoops.sol",
116 |         );
117 | 
118 |         let mut detector = CostlyLoopDetector::default();
119 |         let found = detector.detect(&context).unwrap();
120 |         assert!(found);
121 |         assert_eq!(detector.instances().len(), 1);
122 |     }
123 | }
124 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/pre_declared_variable_usage.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{
  2 |     collections::{BTreeMap, HashSet},
  3 |     error::Error,
  4 | };
  5 | 
  6 | use crate::ast::{ASTNode, NodeID};
  7 | 
  8 | use crate::{
  9 |     capture,
 10 |     context::{
 11 |         browser::{ExtractIdentifiers, ExtractVariableDeclarations},
 12 |         workspace::WorkspaceContext,
 13 |     },
 14 |     detect::{
 15 |         detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 16 |         helpers,
 17 |     },
 18 | };
 19 | use eyre::Result;
 20 | 
 21 | // HOW TO USE THIS TEMPLATE:
 22 | // 1. Copy this file and rename it to the snake_case version of the issue you are detecting.
 23 | // 2. Rename the PreDeclaredLocalVariableUsageDetector struct and impl to your new issue name.
 24 | // 3. Add this file and detector struct to the mod.rs file in the same directory.
 25 | // 4. Implement the detect function to find instances of the issue.
 26 | 
 27 | #[derive(Default)]
 28 | pub struct PreDeclaredLocalVariableUsageDetector {
 29 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 30 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 31 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 32 | }
 33 | 
 34 | impl IssueDetector for PreDeclaredLocalVariableUsageDetector {
 35 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 36 |         // Since this is restricted to local variables, we examine each function independently
 37 |         for function in context.function_definitions().into_iter().filter(|&f| f.implemented) {
 38 |             let local_variable_declaration_ids = ExtractVariableDeclarations::from(function)
 39 |                 .extracted
 40 |                 .iter()
 41 |                 .map(|vd| vd.id)
 42 |                 .collect::<HashSet<_>>();
 43 | 
 44 |             let used_local_variables = ExtractIdentifiers::from(function).extracted;
 45 | 
 46 |             let used_local_variables = used_local_variables
 47 |                 .iter()
 48 |                 .filter(|identifier| {
 49 |                     identifier.referenced_declaration.is_some_and(|referenced_declaration| {
 50 |                         local_variable_declaration_ids.contains(&referenced_declaration)
 51 |                     })
 52 |                 })
 53 |                 .collect::<HashSet<_>>();
 54 | 
 55 |             for used in used_local_variables {
 56 |                 if let Some(id) = used.referenced_declaration
 57 |                     && let Some(ASTNode::VariableDeclaration(variable_declaration)) =
 58 |                         context.nodes.get(&id)
 59 |                 {
 60 |                     let used_offset = helpers::get_node_offset(&used.into());
 61 |                     let declaration_offset = helpers::get_node_offset(&variable_declaration.into());
 62 | 
 63 |                     if let (Some(used_offset), Some(declaration_offset)) =
 64 |                         (used_offset, declaration_offset)
 65 |                         && used_offset < declaration_offset
 66 |                     {
 67 |                         capture!(self, context, used);
 68 |                     }
 69 |                 }
 70 |             }
 71 |         }
 72 | 
 73 |         Ok(!self.found_instances.is_empty())
 74 |     }
 75 | 
 76 |     fn severity(&self) -> IssueSeverity {
 77 |         IssueSeverity::High
 78 |     }
 79 | 
 80 |     fn title(&self) -> String {
 81 |         String::from("Usage of variable before declaration")
 82 |     }
 83 | 
 84 |     fn description(&self) -> String {
 85 |         String::from("Declare the variable before using it to avoid unintended consequences.")
 86 |     }
 87 | 
 88 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 89 |         self.found_instances.clone()
 90 |     }
 91 | 
 92 |     fn name(&self) -> String {
 93 |         IssueDetectorNamePool::PreDeclaredLocalVariableUsage.to_string()
 94 |     }
 95 | }
 96 | 
 97 | #[cfg(test)]
 98 | mod pre_declared_variable_usage_tests {
 99 | 
100 |     use crate::detect::{
101 |         detector::IssueDetector,
102 |         high::pre_declared_variable_usage::PreDeclaredLocalVariableUsageDetector,
103 |     };
104 | 
105 |     #[test]
106 | 
107 |     fn test_pre_declared_variable_usage() {
108 |         let context = crate::detect::test_utils::load_solidity_source_unit(
109 |             "../tests/contract-playground/src/PreDeclaredVarUsage.sol",
110 |         );
111 | 
112 |         let mut detector = PreDeclaredLocalVariableUsageDetector::default();
113 |         let found = detector.detect(&context).unwrap();
114 |         assert!(found);
115 |         assert_eq!(detector.instances().len(), 1);
116 |     }
117 | }
118 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/strict_equality_contract_balance.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, error::Error};
  2 | 
  3 | use crate::ast::{Expression, NodeID};
  4 | 
  5 | use crate::{
  6 |     capture,
  7 |     context::workspace::WorkspaceContext,
  8 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
  9 | };
 10 | use eyre::Result;
 11 | 
 12 | #[derive(Default)]
 13 | pub struct DangerousStrictEqualityOnBalanceDetector {
 14 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 15 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 16 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 17 | }
 18 | 
 19 | impl IssueDetector for DangerousStrictEqualityOnBalanceDetector {
 20 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 21 |         // When you have found an instance of the issue,
 22 |         // use the following macro to add it to `found_instances`:
 23 |         //
 24 |         // capture!(self, context, item);
 25 | 
 26 |         for binary_operation in context
 27 |             .binary_operations()
 28 |             .into_iter()
 29 |             .filter(|&op| op.operator == "==" || op.operator == "!=")
 30 |         {
 31 |             for expr in [
 32 |                 binary_operation.left_expression.as_ref(),
 33 |                 binary_operation.right_expression.as_ref(),
 34 |             ] {
 35 |                 if let Expression::MemberAccess(member_access) = expr
 36 |                     && member_access.member_name == "balance"
 37 |                     && member_access.expression.as_ref().type_descriptions().is_some_and(
 38 |                         |type_desc| {
 39 |                             type_desc.type_string.as_ref().is_some_and(|type_string| {
 40 |                                 // For older solc versions when you say this.balance, "this" is
 41 |                                 // of type contract XXX
 42 |                                 type_string.starts_with("contract ")
 43 |                                     // In newers solidity versions, you say address(this).balance or payable(address(this)).balance
 44 |                                         || type_string == "address"
 45 |                                         || type_string == "address payable"
 46 |                             })
 47 |                         },
 48 |                     )
 49 |                 {
 50 |                     capture!(self, context, binary_operation);
 51 |                 }
 52 |             }
 53 |         }
 54 | 
 55 |         Ok(!self.found_instances.is_empty())
 56 |     }
 57 | 
 58 |     fn severity(&self) -> IssueSeverity {
 59 |         IssueSeverity::High
 60 |     }
 61 | 
 62 |     fn title(&self) -> String {
 63 |         String::from("Dangerous strict equality checks on contract balances")
 64 |     }
 65 | 
 66 |     fn description(&self) -> String {
 67 |         String::from(
 68 |             "A contract's balance can be forcibly manipulated by another selfdestructing contract. Therefore, it's recommended to use >, <, >= or <= instead of strict equality.",
 69 |         )
 70 |     }
 71 | 
 72 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 73 |         self.found_instances.clone()
 74 |     }
 75 | 
 76 |     fn name(&self) -> String {
 77 |         IssueDetectorNamePool::StrictEqualityContractBalance.to_string()
 78 |     }
 79 | }
 80 | 
 81 | #[cfg(test)]
 82 | mod strict_equality_contract_balance_tests {
 83 | 
 84 |     use crate::detect::{
 85 |         detector::IssueDetector,
 86 |         high::strict_equality_contract_balance::DangerousStrictEqualityOnBalanceDetector,
 87 |     };
 88 | 
 89 |     #[test]
 90 | 
 91 |     fn test_strict_equality_contract_balance1() {
 92 |         let context = crate::detect::test_utils::load_solidity_source_unit(
 93 |             "../tests/contract-playground/src/DangerousStrictEquality1.sol",
 94 |         );
 95 | 
 96 |         let mut detector = DangerousStrictEqualityOnBalanceDetector::default();
 97 |         let found = detector.detect(&context).unwrap();
 98 |         assert!(found);
 99 |         assert_eq!(detector.instances().len(), 1);
100 |     }
101 | 
102 |     #[test]
103 |     fn test_strict_equality_contract_balance2() {
104 |         let context = crate::detect::test_utils::load_solidity_source_unit(
105 |             "../tests/contract-playground/src/DangerousStrictEquality2.sol",
106 |         );
107 | 
108 |         let mut detector = DangerousStrictEqualityOnBalanceDetector::default();
109 |         let found = detector.detect(&context).unwrap();
110 |         assert!(found);
111 |         assert_eq!(detector.instances().len(), 2);
112 |     }
113 | }
114 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/unused_state_variable.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{
  2 |     collections::{BTreeMap, BTreeSet},
  3 |     error::Error,
  4 | };
  5 | 
  6 | use crate::ast::{ASTNode, ContractKind, NodeID, NodeType, Visibility};
  7 | 
  8 | use crate::{
  9 |     capture,
 10 |     context::{
 11 |         browser::{
 12 |             ExtractReferencedDeclarations, ExtractVariableDeclarations, GetClosestAncestorOfTypeX,
 13 |         },
 14 |         workspace::WorkspaceContext,
 15 |     },
 16 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 17 | };
 18 | use eyre::Result;
 19 | 
 20 | #[derive(Default)]
 21 | pub struct UnusedStateVariablesDetector {
 22 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 23 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 24 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 25 | }
 26 | 
 27 | impl IssueDetector for UnusedStateVariablesDetector {
 28 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 29 |         // Collect all referencedDeclaration IDs and StateVariableDeclarationIDs
 30 |         let mut all_referenced_declarations = BTreeSet::new();
 31 |         let mut all_state_variable_declarations = BTreeSet::new();
 32 | 
 33 |         for source_unit in context.source_units() {
 34 |             let referenced_declarations =
 35 |                 ExtractReferencedDeclarations::from(source_unit).extracted;
 36 |             all_referenced_declarations.extend(referenced_declarations);
 37 |             let variable_declarations = ExtractVariableDeclarations::from(source_unit).extracted;
 38 |             all_state_variable_declarations.extend(
 39 |                 variable_declarations
 40 |                     .into_iter()
 41 |                     .filter(|v| {
 42 |                         v.state_variable
 43 |                             && (v.visibility == Visibility::Private
 44 |                                 || v.visibility == Visibility::Internal)
 45 |                     })
 46 |                     .map(|v| v.id),
 47 |             )
 48 |         }
 49 | 
 50 |         // Now, retain only the ones that have not been referenced
 51 |         all_state_variable_declarations.retain(|v| !all_referenced_declarations.contains(v));
 52 | 
 53 |         for unused_state_var_id in all_state_variable_declarations {
 54 |             if let Some(node) = context.nodes.get(&unused_state_var_id) {
 55 |                 if let Some(ASTNode::ContractDefinition(contract)) =
 56 |                     node.closest_ancestor_of_type(context, NodeType::ContractDefinition)
 57 |                 {
 58 |                     // If this variable is defined inside a contract, make sure it's not an abstract
 59 |                     // contract before capturing it
 60 |                     if !contract.is_abstract && contract.kind == ContractKind::Contract {
 61 |                         capture!(self, context, node);
 62 |                     }
 63 |                 } else {
 64 |                     // Otherwise, just capture it !
 65 |                     capture!(self, context, node);
 66 |                 }
 67 |             }
 68 |         }
 69 | 
 70 |         Ok(!self.found_instances.is_empty())
 71 |     }
 72 | 
 73 |     fn severity(&self) -> IssueSeverity {
 74 |         IssueSeverity::Low
 75 |     }
 76 | 
 77 |     fn title(&self) -> String {
 78 |         String::from("Unused State Variable")
 79 |     }
 80 | 
 81 |     fn description(&self) -> String {
 82 |         String::from(
 83 |             "State variable appears to be unused. No analysis has been performed to see if any inline assembly \
 84 |             references it. Consider removing this unused variable.",
 85 |         )
 86 |     }
 87 | 
 88 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 89 |         self.found_instances.clone()
 90 |     }
 91 | 
 92 |     fn name(&self) -> String {
 93 |         format!("{}", IssueDetectorNamePool::UnusedStateVariable)
 94 |     }
 95 | }
 96 | 
 97 | #[cfg(test)]
 98 | mod unused_detector_tests {
 99 | 
100 |     use crate::detect::{
101 |         detector::IssueDetector, low::unused_state_variable::UnusedStateVariablesDetector,
102 |     };
103 | 
104 |     #[test]
105 | 
106 |     fn test_unused_state_variables() {
107 |         let context = crate::detect::test_utils::load_solidity_source_unit(
108 |             "../tests/contract-playground/src/UnusedStateVariables.sol",
109 |         );
110 | 
111 |         let mut detector = UnusedStateVariablesDetector::default();
112 |         let found = detector.detect(&context).unwrap();
113 |         assert!(found);
114 |         assert_eq!(detector.instances().len(), 4);
115 |     }
116 | }
117 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/assert_state_change.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, convert::identity, error::Error};
  2 | 
  3 | use crate::ast::{Expression, Identifier, NodeID};
  4 | 
  5 | use crate::{
  6 |     capture,
  7 |     context::workspace::WorkspaceContext,
  8 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
  9 | };
 10 | use eyre::Result;
 11 | 
 12 | #[derive(Default)]
 13 | pub struct AssertStateChangeDetector {
 14 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 15 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 16 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 17 | }
 18 | 
 19 | impl IssueDetector for AssertStateChangeDetector {
 20 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 21 |         for function_call in context.function_calls() {
 22 |             if let Expression::Identifier(Identifier { name, .. }) =
 23 |                 function_call.expression.as_ref()
 24 |                 && name == "assert"
 25 |                 && function_call.arguments_change_contract_state(context).is_some_and(identity)
 26 |             {
 27 |                 capture!(self, context, function_call);
 28 |             }
 29 |         }
 30 | 
 31 |         Ok(!self.found_instances.is_empty())
 32 |     }
 33 | 
 34 |     fn severity(&self) -> IssueSeverity {
 35 |         IssueSeverity::Low
 36 |     }
 37 | 
 38 |     fn title(&self) -> String {
 39 |         String::from("State change in `assert()` statement")
 40 |     }
 41 | 
 42 |     fn description(&self) -> String {
 43 |         String::from(
 44 |             "An argument to `assert()` modifies the state. Use `require` for invariants modifying state.",
 45 |         )
 46 |     }
 47 | 
 48 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 49 |         self.found_instances.clone()
 50 |     }
 51 | 
 52 |     fn name(&self) -> String {
 53 |         format!("{}", IssueDetectorNamePool::AssertStateChange)
 54 |     }
 55 | }
 56 | 
 57 | mod assert_state_change_tracker {
 58 |     use crate::{
 59 |         ast::{ASTNode, FunctionCall},
 60 |         context::{
 61 |             browser::ApproximateStorageChangeFinder,
 62 |             graph::{CallGraphConsumer, CallGraphDirection, CallGraphVisitor},
 63 |             workspace::WorkspaceContext,
 64 |         },
 65 |     };
 66 | 
 67 |     struct StateVariableChangeTracker<'a> {
 68 |         has_some_state_variable_changed: bool,
 69 |         context: &'a WorkspaceContext,
 70 |     }
 71 | 
 72 |     impl CallGraphVisitor for StateVariableChangeTracker<'_> {
 73 |         fn visit_any(&mut self, node: &crate::ast::ASTNode) -> eyre::Result<()> {
 74 |             if self.has_some_state_variable_changed {
 75 |                 return Ok(());
 76 |             }
 77 |             let finder = ApproximateStorageChangeFinder::from(self.context, node);
 78 |             if finder.state_variables_have_been_manipulated() {
 79 |                 self.has_some_state_variable_changed = true;
 80 |             }
 81 |             Ok(())
 82 |         }
 83 |     }
 84 | 
 85 |     impl FunctionCall {
 86 |         pub fn arguments_change_contract_state(&self, context: &WorkspaceContext) -> Option<bool> {
 87 |             let arguments =
 88 |                 self.arguments.clone().into_iter().map(|n| n.into()).collect::<Vec<ASTNode>>();
 89 |             let ast_nodes: &[&ASTNode] = &(arguments.iter().collect::<Vec<_>>());
 90 | 
 91 |             let callgraphs =
 92 |                 CallGraphConsumer::get(context, ast_nodes, CallGraphDirection::Inward).ok()?;
 93 | 
 94 |             for callgraph in callgraphs {
 95 |                 let mut tracker =
 96 |                     StateVariableChangeTracker { has_some_state_variable_changed: false, context };
 97 |                 callgraph.accept(context, &mut tracker).ok()?;
 98 |                 if tracker.has_some_state_variable_changed {
 99 |                     return Some(true);
100 |                 }
101 |             }
102 | 
103 |             Some(false)
104 |         }
105 |     }
106 | }
107 | 
108 | #[cfg(test)]
109 | mod assert_state_changes_tests {
110 | 
111 |     use crate::detect::{
112 |         detector::IssueDetector, low::assert_state_change::AssertStateChangeDetector,
113 |     };
114 | 
115 |     #[test]
116 | 
117 |     fn test_assert_state_change() {
118 |         let context = crate::detect::test_utils::load_solidity_source_unit(
119 |             "../tests/contract-playground/src/AssertStateChange.sol",
120 |         );
121 | 
122 |         let mut detector = AssertStateChangeDetector::default();
123 |         let found = detector.detect(&context).unwrap();
124 | 
125 |         assert!(found);
126 |         assert_eq!(detector.instances().len(), 1);
127 |     }
128 | }
129 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/msg_value_in_loops.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, convert::identity, error::Error};
  2 | 
  3 | use crate::ast::{ASTNode, Expression, NodeID};
  4 | 
  5 | use crate::{
  6 |     capture,
  7 |     context::{
  8 |         browser::ExtractMemberAccesses,
  9 |         graph::{CallGraphConsumer, CallGraphDirection, CallGraphVisitor},
 10 |         workspace::WorkspaceContext,
 11 |     },
 12 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 13 | };
 14 | use eyre::Result;
 15 | 
 16 | #[derive(Default)]
 17 | pub struct MsgValueUsedInLoopDetector {
 18 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 19 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 20 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 21 | }
 22 | 
 23 | impl IssueDetector for MsgValueUsedInLoopDetector {
 24 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 25 |         // Investigate for loops to check for usage of `msg.value`
 26 |         for for_statement in context.for_statements() {
 27 |             if uses_msg_value(context, &(for_statement.into())).is_some_and(identity) {
 28 |                 capture!(self, context, for_statement);
 29 |             }
 30 |         }
 31 | 
 32 |         // Investigate while loops to check for usage of `msg.value`
 33 |         for while_statement in context.while_statements() {
 34 |             if uses_msg_value(context, &(while_statement.into())).is_some_and(identity) {
 35 |                 capture!(self, context, while_statement);
 36 |             }
 37 |         }
 38 | 
 39 |         // Investigate the do while loops to check for usage of `msg.value`
 40 |         for do_while_statement in context.do_while_statements() {
 41 |             if uses_msg_value(context, &(do_while_statement.into())).is_some_and(identity) {
 42 |                 capture!(self, context, do_while_statement);
 43 |             }
 44 |         }
 45 | 
 46 |         Ok(!self.found_instances.is_empty())
 47 |     }
 48 | 
 49 |     fn severity(&self) -> IssueSeverity {
 50 |         IssueSeverity::High
 51 |     }
 52 | 
 53 |     fn title(&self) -> String {
 54 |         String::from("Loop contains `msg.value`")
 55 |     }
 56 | 
 57 |     fn description(&self) -> String {
 58 |         String::from(
 59 |             "Provide an explicit array of amounts alongside the receivers array, and check that the sum of all amounts matches `msg.value`.",
 60 |         )
 61 |     }
 62 | 
 63 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 64 |         self.found_instances.clone()
 65 |     }
 66 | 
 67 |     fn name(&self) -> String {
 68 |         IssueDetectorNamePool::MsgValueInLoop.to_string()
 69 |     }
 70 | }
 71 | 
 72 | fn uses_msg_value(context: &WorkspaceContext, ast_node: &ASTNode) -> Option<bool> {
 73 |     let callgraphs =
 74 |         CallGraphConsumer::get(context, &[ast_node], CallGraphDirection::Inward).ok()?;
 75 | 
 76 |     for callgraph in callgraphs {
 77 |         let mut tracker = MsgValueTracker::default();
 78 |         callgraph.accept(context, &mut tracker).ok()?;
 79 |         if tracker.has_msg_value {
 80 |             return Some(true);
 81 |         }
 82 |     }
 83 |     Some(false)
 84 | }
 85 | 
 86 | #[derive(Default)]
 87 | struct MsgValueTracker {
 88 |     has_msg_value: bool,
 89 | }
 90 | 
 91 | impl CallGraphVisitor for MsgValueTracker {
 92 |     fn visit_any(&mut self, node: &crate::ast::ASTNode) -> eyre::Result<()> {
 93 |         if !self.has_msg_value
 94 |             && ExtractMemberAccesses::from(node).extracted.iter().any(|member_access| {
 95 |                 member_access.member_name == "value"
 96 |                     && if let Expression::Identifier(identifier) = member_access.expression.as_ref()
 97 |                     {
 98 |                         identifier.name == "msg"
 99 |                     } else {
100 |                         false
101 |                     }
102 |             })
103 |         {
104 |             self.has_msg_value = true;
105 |         }
106 | 
107 |         Ok(())
108 |     }
109 | }
110 | 
111 | #[cfg(test)]
112 | mod msg_value_in_loop_detector {
113 | 
114 |     use crate::detect::{
115 |         detector::IssueDetector, high::msg_value_in_loops::MsgValueUsedInLoopDetector,
116 |     };
117 | 
118 |     #[test]
119 | 
120 |     fn test_msg_value_in_loop() {
121 |         let context = crate::detect::test_utils::load_solidity_source_unit(
122 |             "../tests/contract-playground/src/MsgValueInLoop.sol",
123 |         );
124 | 
125 |         let mut detector = MsgValueUsedInLoopDetector::default();
126 |         let found = detector.detect(&context).unwrap();
127 |         assert!(found);
128 |         assert_eq!(detector.instances().len(), 4);
129 |     }
130 | }
131 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/context/router/modifier_calls.rs:
--------------------------------------------------------------------------------

```rust
  1 | use super::Router;
  2 | use crate::{
  3 |     ast::{
  4 |         ASTNode, ContractDefinition, ContractKind, IdentifierOrIdentifierPath, ModifierDefinition,
  5 |         ModifierInvocation, NodeID, NodeType,
  6 |     },
  7 |     context::{browser::GetClosestAncestorOfTypeX, workspace::WorkspaceContext},
  8 | };
  9 | use std::collections::{HashMap, hash_map::Entry};
 10 | 
 11 | impl Router {
 12 |     pub(super) fn _resolve_modifier_call<'a>(
 13 |         &self,
 14 |         context: &'a WorkspaceContext,
 15 |         base_contract: &'a ContractDefinition,
 16 |         modifier_call: &'a ModifierInvocation,
 17 |     ) -> Option<&'a ModifierDefinition> {
 18 |         // check if it's illegal base contract type
 19 |         if !base_contract.is_deployable_contract() {
 20 |             return None;
 21 |         }
 22 | 
 23 |         // check if it's illegal value - i.e function call that cannot be called from the base
 24 |         // contract must be discarded
 25 |         if let Some(ASTNode::ContractDefinition(caller_contract)) =
 26 |             modifier_call.closest_ancestor_of_type(context, NodeType::ContractDefinition)
 27 |         {
 28 |             if caller_contract.kind == ContractKind::Contract
 29 |                 && !caller_contract.is_in(context, base_contract)
 30 |             {
 31 |                 return None;
 32 |             } else if caller_contract.kind == ContractKind::Library {
 33 |                 // If an internal modifier call happens from a library, suspect cannot be overridden
 34 |                 // As of now, libraries do not have inheritance
 35 |                 //
 36 |                 // NOTE: for this case, we don't check that the modifier call from library can
 37 |                 // actually happen and is trigger(able) by the base contract.
 38 |                 let aux_modifier = modifier_call.suspected_target_modifier(context)?;
 39 |                 return Some(aux_modifier);
 40 |             }
 41 |         }
 42 | 
 43 |         self.perform_mc_lookup_through_inheritance_tree_and_fallback_to_suspect(
 44 |             context,
 45 |             base_contract,
 46 |             modifier_call,
 47 |         )
 48 |     }
 49 | 
 50 |     fn perform_mc_lookup_through_inheritance_tree_and_fallback_to_suspect<'a>(
 51 |         &self,
 52 |         context: &'a WorkspaceContext,
 53 |         base_contract: &'a ContractDefinition,
 54 |         modifier_call: &'a ModifierInvocation,
 55 |     ) -> Option<&'a ModifierDefinition> {
 56 |         let aux_modifier = modifier_call.suspected_target_modifier(context)?;
 57 |         let selectorish = aux_modifier.selectorish();
 58 |         let base_index = self.modifier_calls.get(&base_contract.id)?;
 59 | 
 60 |         let resolve = |starting_point: &ContractDefinition| -> Option<&ModifierDefinition> {
 61 |             let starting_point = starting_point.id;
 62 |             let lookup_index = base_index.routes.get(&starting_point)?;
 63 |             match lookup_index.get(&selectorish) {
 64 |                 Some(modifier_id) => match context.nodes.get(modifier_id) {
 65 |                     Some(ASTNode::ModifierDefinition(modifier_def)) => Some(modifier_def),
 66 |                     _ => None,
 67 |                 },
 68 |                 // if not found in lookup fallback to aux function (suspect function)
 69 |                 None => Some(aux_modifier),
 70 |             }
 71 |         };
 72 | 
 73 |         // TODO: Investigate when other enumeration can be triggered.
 74 |         if let IdentifierOrIdentifierPath::IdentifierPath(p) = &modifier_call.modifier_name {
 75 |             // Ex: `B.modify` is a full path so then the suspected target must be right.
 76 |             if p.name.contains('.') {
 77 |                 return Some(aux_modifier);
 78 |             }
 79 |             // Ex: `modify`
 80 |             return resolve(base_contract);
 81 |         }
 82 | 
 83 |         None
 84 |     }
 85 | }
 86 | 
 87 | pub(super) fn build_mc_router_for_contract(
 88 |     context: &WorkspaceContext,
 89 |     base_contract: &ContractDefinition,
 90 | ) -> HashMap<NodeID, HashMap<String, NodeID>> {
 91 |     let c3 = base_contract.c3(context).collect::<Vec<_>>();
 92 |     let mut base_routes = HashMap::new();
 93 |     for (idx, starting_point) in c3.iter().enumerate() {
 94 |         let mut routes = HashMap::new();
 95 |         for contract in c3.iter().skip(idx) {
 96 |             for modifier in contract.modifier_definitions() {
 97 |                 if let Entry::Vacant(e) = routes.entry(modifier.selectorish()) {
 98 |                     e.insert(modifier.id);
 99 |                 }
100 |             }
101 |         }
102 |         base_routes.insert(starting_point.id, routes);
103 |     }
104 |     base_routes
105 | }
106 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/delete_nested_mapping.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, error::Error};
  2 | 
  3 | use crate::ast::{
  4 |     ASTNode, Expression, Identifier, IndexAccess, Mapping, NodeID, TypeName, UserDefinedTypeName,
  5 |     VariableDeclaration,
  6 | };
  7 | 
  8 | use crate::{
  9 |     capture,
 10 |     context::workspace::WorkspaceContext,
 11 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 12 | };
 13 | use eyre::Result;
 14 | 
 15 | #[derive(Default)]
 16 | pub struct DeletionNestedMappingDetector {
 17 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 18 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 19 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 20 | }
 21 | 
 22 | impl IssueDetector for DeletionNestedMappingDetector {
 23 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 24 |         for delete_operation in
 25 |             context.unary_operations().into_iter().filter(|op| op.operator == "delete")
 26 |         {
 27 |             if let Expression::IndexAccess(IndexAccess { base_expression, .. }) =
 28 |                 delete_operation.sub_expression.as_ref()
 29 |                 && let Expression::Identifier(Identifier {
 30 |                     referenced_declaration: Some(referenced_id),
 31 |                     type_descriptions,
 32 |                     ..
 33 |                 }) = base_expression.as_ref()
 34 |             {
 35 |                 // Check if we're deleting a value from mapping
 36 |                 if type_descriptions
 37 |                     .type_string
 38 |                     .as_ref()
 39 |                     .is_some_and(|type_string| type_string.starts_with("mapping"))
 40 |                 {
 41 |                     // Check if the value in the mapping is of type struct that has a member
 42 |                     // which is also a mapping
 43 |                     if let Some(ASTNode::VariableDeclaration(VariableDeclaration {
 44 |                         type_name: Some(TypeName::Mapping(Mapping { value_type, .. })),
 45 |                         ..
 46 |                     })) = context.nodes.get(referenced_id)
 47 |                         && let TypeName::UserDefinedTypeName(UserDefinedTypeName {
 48 |                             referenced_declaration,
 49 |                             ..
 50 |                         }) = value_type.as_ref()
 51 |                         && let Some(ASTNode::StructDefinition(structure)) =
 52 |                             context.nodes.get(referenced_declaration)
 53 |                     {
 54 |                         // Check that a member of a struct is of type mapping
 55 |                         if structure.members.iter().any(|member| {
 56 |                             member
 57 |                                 .type_descriptions
 58 |                                 .type_string
 59 |                                 .as_ref()
 60 |                                 .is_some_and(|type_string| type_string.starts_with("mapping"))
 61 |                         }) {
 62 |                             capture!(self, context, delete_operation);
 63 |                         }
 64 |                     }
 65 |                 }
 66 |             }
 67 |         }
 68 | 
 69 |         Ok(!self.found_instances.is_empty())
 70 |     }
 71 | 
 72 |     fn severity(&self) -> IssueSeverity {
 73 |         IssueSeverity::High
 74 |     }
 75 | 
 76 |     fn title(&self) -> String {
 77 |         String::from("Deletion from a nested mapping")
 78 |     }
 79 | 
 80 |     fn description(&self) -> String {
 81 |         String::from(
 82 |             "A deletion in a structure containing a mapping will not delete the mapping. The remaining data may be used to compromise the contract.",
 83 |         )
 84 |     }
 85 | 
 86 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 87 |         self.found_instances.clone()
 88 |     }
 89 | 
 90 |     fn name(&self) -> String {
 91 |         IssueDetectorNamePool::DeleteNestedMapping.to_string()
 92 |     }
 93 | }
 94 | 
 95 | #[cfg(test)]
 96 | mod deletion_nested_mapping_tests {
 97 | 
 98 |     use crate::detect::{
 99 |         detector::IssueDetector, high::delete_nested_mapping::DeletionNestedMappingDetector,
100 |     };
101 | 
102 |     #[test]
103 | 
104 |     fn test_deletion_nested_mapping() {
105 |         let context = crate::detect::test_utils::load_solidity_source_unit(
106 |             "../tests/contract-playground/src/DeletionNestedMappingStructureContract.sol",
107 |         );
108 | 
109 |         let mut detector = DeletionNestedMappingDetector::default();
110 |         let found = detector.detect(&context).unwrap();
111 |         assert!(found);
112 |         assert_eq!(detector.instances().len(), 1);
113 |     }
114 | }
115 | 
```

--------------------------------------------------------------------------------
/aderyn_driver/src/interface/lsp.rs:
--------------------------------------------------------------------------------

```rust
  1 | use aderyn_core::report::*;
  2 | use std::{collections::BTreeMap, path::Path};
  3 | use tower_lsp::lsp_types::{Diagnostic, DiagnosticSeverity, Position, Range, Url};
  4 | 
  5 | /// Report structure that is tailored to aid LSP
  6 | pub struct LspReport {
  7 |     pub high_issues: HighIssues,
  8 |     pub low_issues: LowIssues,
  9 |     pub diagnostics: BTreeMap<Url, Vec<Diagnostic>>,
 10 | }
 11 | 
 12 | impl LspReport {
 13 |     pub fn from(low_issues: LowIssues, high_issues: HighIssues, root_rel_path: &Path) -> Self {
 14 |         fn create_diagnostic_from_issue(
 15 |             issue_body: &IssueBody,
 16 |             instance: &IssueInstance,
 17 |             severity: DiagnosticSeverity,
 18 |             root_rel_path: &Path,
 19 |         ) -> Option<(Url, Diagnostic)> {
 20 |             // Line number
 21 |             let line_no = instance.line_no.checked_sub(1)?;
 22 | 
 23 |             // Character position and range from the start of the line number
 24 |             let (pos_start, pos_range) = instance.src_char2.split_once(':')?;
 25 |             let pos_start = pos_start.parse::<u32>().unwrap_or_default().checked_sub(1)?;
 26 |             let pos_range = pos_range.parse::<u32>().unwrap_or_default();
 27 | 
 28 |             // Craft the diagnostic message
 29 |             let mut message = format!("Title: {}\n", issue_body.title);
 30 | 
 31 |             if !issue_body.description.is_empty() {
 32 |                 message.push_str(&format!("\nDescription: {}\n", issue_body.description));
 33 |             }
 34 | 
 35 |             if let Some(hint) = instance.hint.clone()
 36 |                 && !hint.is_empty()
 37 |             {
 38 |                 message.push_str(&format!("\nHint: {}\n", hint));
 39 |             }
 40 | 
 41 |             message.push_str(&format!(
 42 |                "\nTo ignore this warning, add:\n\n// aderyn-ignore-next-line({})\n\nor mark as false positive:\n\n// aderyn-fp-next-line({})\n\n",
 43 |                 issue_body.detector_name,
 44 |                 issue_body.detector_name,
 45 |             ));
 46 | 
 47 |             // Make the diagnostic that LSP can understand
 48 |             let diagnostic = Diagnostic {
 49 |                 range: Range {
 50 |                     start: Position { line: line_no as u32, character: pos_start },
 51 |                     end: Position { line: line_no as u32, character: pos_start + pos_range },
 52 |                 },
 53 |                 severity: Some(severity),
 54 |                 message,
 55 |                 code: None,
 56 |                 code_description: None,
 57 |                 source: Some("Aderyn".to_string()),
 58 |                 related_information: None,
 59 |                 tags: None,
 60 |                 data: None,
 61 |             };
 62 |             let mut full_contract_path = root_rel_path.to_path_buf();
 63 |             full_contract_path.push(instance.contract_path.clone());
 64 |             let full_contract_path = full_contract_path.canonicalize().ok()?;
 65 |             let full_contract_path_string = full_contract_path.to_string_lossy().to_string();
 66 |             let file_uri = Url::parse(&format!("file://{}", &full_contract_path_string)).ok()?;
 67 | 
 68 |             Some((file_uri, diagnostic))
 69 |         }
 70 | 
 71 |         let mut diagnostics = BTreeMap::new();
 72 | 
 73 |         for issue_body in &high_issues.issues {
 74 |             for instance in &issue_body.instances {
 75 |                 let Some((file_url, diagnostic)) = create_diagnostic_from_issue(
 76 |                     issue_body,
 77 |                     instance,
 78 |                     DiagnosticSeverity::WARNING,
 79 |                     root_rel_path,
 80 |                 ) else {
 81 |                     continue;
 82 |                 };
 83 | 
 84 |                 let file_diagnostics: &mut Vec<Diagnostic> =
 85 |                     diagnostics.entry(file_url).or_default();
 86 | 
 87 |                 file_diagnostics.push(diagnostic);
 88 |             }
 89 |         }
 90 |         for issue_body in &low_issues.issues {
 91 |             for instance in &issue_body.instances {
 92 |                 let Some((file_url, diagnostic)) = create_diagnostic_from_issue(
 93 |                     issue_body,
 94 |                     instance,
 95 |                     DiagnosticSeverity::INFORMATION,
 96 |                     root_rel_path,
 97 |                 ) else {
 98 |                     continue;
 99 |                 };
100 | 
101 |                 let file_diagnostics: &mut Vec<Diagnostic> =
102 |                     diagnostics.entry(file_url).or_default();
103 | 
104 |                 file_diagnostics.push(diagnostic);
105 |             }
106 |         }
107 |         Self { low_issues, high_issues, diagnostics }
108 |     }
109 | }
110 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/eth_send_unchecked_address.rs:
--------------------------------------------------------------------------------

```rust
  1 | use std::{collections::BTreeMap, error::Error};
  2 | 
  3 | use crate::ast::NodeID;
  4 | 
  5 | use crate::{
  6 |     capture,
  7 |     context::{
  8 |         browser::ExtractModifierInvocations,
  9 |         graph::CallGraphVisitor,
 10 |         workspace::{ASTNode, WorkspaceContext},
 11 |     },
 12 |     detect::{
 13 |         detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 14 |         helpers,
 15 |     },
 16 | };
 17 | use eyre::Result;
 18 | 
 19 | #[derive(Default)]
 20 | pub struct SendEtherNoChecksDetector {
 21 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
 22 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
 23 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
 24 | }
 25 | 
 26 | impl IssueDetector for SendEtherNoChecksDetector {
 27 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
 28 |         for (func, callgraphs) in context.entrypoints_with_callgraphs() {
 29 |             for callgraph in callgraphs {
 30 |                 let mut tracker = AddressChecksAndCallWithValueTracker::default();
 31 |                 callgraph.accept(context, &mut tracker)?;
 32 | 
 33 |                 // Hacky way to check if the modifier is a know msg.sender checking modifier
 34 |                 // This is because our Callgraph doesn't navigate inside contracts that are outside
 35 |                 // the scope, this includes imported contracts.
 36 |                 let has_oz_modifier =
 37 |                     ExtractModifierInvocations::from(func).extracted.iter().any(|invocation| {
 38 |                         invocation.modifier_name.name().contains("onlyRole")
 39 |                             || invocation.modifier_name.name() == "onlyOwner"
 40 |                             || invocation.modifier_name.name() == "requiresAuth"
 41 |                     });
 42 | 
 43 |                 if tracker.sends_native_eth
 44 |                     && !tracker.has_binary_checks_on_some_address
 45 |                     && !has_oz_modifier
 46 |                 {
 47 |                     capture!(self, context, func);
 48 |                 }
 49 |             }
 50 |         }
 51 | 
 52 |         Ok(!self.found_instances.is_empty())
 53 |     }
 54 | 
 55 |     fn severity(&self) -> IssueSeverity {
 56 |         IssueSeverity::High
 57 |     }
 58 | 
 59 |     fn title(&self) -> String {
 60 |         String::from("ETH transferred without address checks")
 61 |     }
 62 | 
 63 |     fn description(&self) -> String {
 64 |         String::from(
 65 |             "Consider introducing checks for `msg.sender` to ensure the recipient of the money is as intended.",
 66 |         )
 67 |     }
 68 | 
 69 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
 70 |         self.found_instances.clone()
 71 |     }
 72 | 
 73 |     fn name(&self) -> String {
 74 |         IssueDetectorNamePool::EthSendUncheckedAddress.to_string()
 75 |     }
 76 | }
 77 | 
 78 | #[derive(Default)]
 79 | pub struct AddressChecksAndCallWithValueTracker {
 80 |     pub has_binary_checks_on_some_address: bool,
 81 |     pub sends_native_eth: bool,
 82 | }
 83 | 
 84 | impl CallGraphVisitor for AddressChecksAndCallWithValueTracker {
 85 |     fn visit_any(&mut self, node: &ASTNode) -> eyre::Result<()> {
 86 |         if !self.has_binary_checks_on_some_address
 87 |             && helpers::has_binary_checks_on_some_address(node)
 88 |         {
 89 |             self.has_binary_checks_on_some_address = true;
 90 |         }
 91 |         if !self.sends_native_eth && helpers::has_calls_that_sends_native_eth(node) {
 92 |             self.sends_native_eth = true;
 93 |         }
 94 |         eyre::Ok(())
 95 |     }
 96 | }
 97 | 
 98 | #[cfg(test)]
 99 | mod send_ether_no_checks_detector_tests {
100 | 
101 |     use crate::detect::{
102 |         detector::IssueDetector, high::eth_send_unchecked_address::SendEtherNoChecksDetector,
103 |     };
104 | 
105 |     #[test]
106 |     fn test_send_ether_no_checks_lib_import() {
107 |         let context = crate::detect::test_utils::load_solidity_source_unit(
108 |             "../tests/contract-playground/src/SendEtherNoChecksLibImport.sol",
109 |         );
110 | 
111 |         let mut detector = SendEtherNoChecksDetector::default();
112 |         let found = detector.detect(&context).unwrap();
113 |         assert!(!found);
114 |         assert_eq!(detector.instances().len(), 0);
115 |     }
116 | 
117 |     #[test]
118 |     fn test_send_ether_no_checks() {
119 |         let context = crate::detect::test_utils::load_solidity_source_unit(
120 |             "../tests/contract-playground/src/SendEtherNoChecks.sol",
121 |         );
122 | 
123 |         let mut detector = SendEtherNoChecksDetector::default();
124 |         let found = detector.detect(&context).unwrap();
125 |         assert!(found);
126 |         assert_eq!(detector.instances().len(), 3);
127 |     }
128 | }
129 | 
```

--------------------------------------------------------------------------------
/tests/hardhat-js-playground/test/Lock.js:
--------------------------------------------------------------------------------

```javascript
  1 | const {
  2 |   time,
  3 |   loadFixture,
  4 | } = require("@nomicfoundation/hardhat-toolbox/network-helpers");
  5 | const { anyValue } = require("@nomicfoundation/hardhat-chai-matchers/withArgs");
  6 | const { expect } = require("chai");
  7 | 
  8 | describe("Lock", function () {
  9 |   // We define a fixture to reuse the same setup in every test.
 10 |   // We use loadFixture to run this setup once, snapshot that state,
 11 |   // and reset Hardhat Network to that snapshot in every test.
 12 |   async function deployOneYearLockFixture() {
 13 |     const ONE_YEAR_IN_SECS = 365 * 24 * 60 * 60;
 14 |     const ONE_GWEI = 1_000_000_000;
 15 | 
 16 |     const lockedAmount = ONE_GWEI;
 17 |     const unlockTime = (await time.latest()) + ONE_YEAR_IN_SECS;
 18 | 
 19 |     // Contracts are deployed using the first signer/account by default
 20 |     const [owner, otherAccount] = await ethers.getSigners();
 21 | 
 22 |     const Lock = await ethers.getContractFactory("Lock");
 23 |     const lock = await Lock.deploy(unlockTime, { value: lockedAmount });
 24 | 
 25 |     return { lock, unlockTime, lockedAmount, owner, otherAccount };
 26 |   }
 27 | 
 28 |   describe("Deployment", function () {
 29 |     it("Should set the right unlockTime", async function () {
 30 |       const { lock, unlockTime } = await loadFixture(deployOneYearLockFixture);
 31 | 
 32 |       expect(await lock.unlockTime()).to.equal(unlockTime);
 33 |     });
 34 | 
 35 |     it("Should set the right owner", async function () {
 36 |       const { lock, owner } = await loadFixture(deployOneYearLockFixture);
 37 | 
 38 |       expect(await lock.owner()).to.equal(owner.address);
 39 |     });
 40 | 
 41 |     it("Should receive and store the funds to lock", async function () {
 42 |       const { lock, lockedAmount } = await loadFixture(
 43 |         deployOneYearLockFixture
 44 |       );
 45 | 
 46 |       expect(await ethers.provider.getBalance(lock.target)).to.equal(
 47 |         lockedAmount
 48 |       );
 49 |     });
 50 | 
 51 |     it("Should fail if the unlockTime is not in the future", async function () {
 52 |       // We don't use the fixture here because we want a different deployment
 53 |       const latestTime = await time.latest();
 54 |       const Lock = await ethers.getContractFactory("Lock");
 55 |       await expect(Lock.deploy(latestTime, { value: 1 })).to.be.revertedWith(
 56 |         "Unlock time should be in the future"
 57 |       );
 58 |     });
 59 |   });
 60 | 
 61 |   describe("Withdrawals", function () {
 62 |     describe("Validations", function () {
 63 |       it("Should revert with the right error if called too soon", async function () {
 64 |         const { lock } = await loadFixture(deployOneYearLockFixture);
 65 | 
 66 |         await expect(lock.withdraw()).to.be.revertedWith(
 67 |           "You can't withdraw yet"
 68 |         );
 69 |       });
 70 | 
 71 |       it("Should revert with the right error if called from another account", async function () {
 72 |         const { lock, unlockTime, otherAccount } = await loadFixture(
 73 |           deployOneYearLockFixture
 74 |         );
 75 | 
 76 |         // We can increase the time in Hardhat Network
 77 |         await time.increaseTo(unlockTime);
 78 | 
 79 |         // We use lock.connect() to send a transaction from another account
 80 |         await expect(lock.connect(otherAccount).withdraw()).to.be.revertedWith(
 81 |           "You aren't the owner"
 82 |         );
 83 |       });
 84 | 
 85 |       it("Shouldn't fail if the unlockTime has arrived and the owner calls it", async function () {
 86 |         const { lock, unlockTime } = await loadFixture(
 87 |           deployOneYearLockFixture
 88 |         );
 89 | 
 90 |         // Transactions are sent using the first signer by default
 91 |         await time.increaseTo(unlockTime);
 92 | 
 93 |         await expect(lock.withdraw()).not.to.be.reverted;
 94 |       });
 95 |     });
 96 | 
 97 |     describe("Events", function () {
 98 |       it("Should emit an event on withdrawals", async function () {
 99 |         const { lock, unlockTime, lockedAmount } = await loadFixture(
100 |           deployOneYearLockFixture
101 |         );
102 | 
103 |         await time.increaseTo(unlockTime);
104 | 
105 |         await expect(lock.withdraw())
106 |           .to.emit(lock, "Withdrawal")
107 |           .withArgs(lockedAmount, anyValue); // We accept any value as `when` arg
108 |       });
109 |     });
110 | 
111 |     describe("Transfers", function () {
112 |       it("Should transfer the funds to the owner", async function () {
113 |         const { lock, unlockTime, lockedAmount, owner } = await loadFixture(
114 |           deployOneYearLockFixture
115 |         );
116 | 
117 |         await time.increaseTo(unlockTime);
118 | 
119 |         await expect(lock.withdraw()).to.changeEtherBalances(
120 |           [owner, lock],
121 |           [lockedAmount, -lockedAmount]
122 |         );
123 |       });
124 |     });
125 |   });
126 | });
127 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/ast/impls/node/contracts.rs:
--------------------------------------------------------------------------------

```rust
  1 | use crate::{ast::*, visitor::ast_visitor::*};
  2 | use eyre::Result;
  3 | 
  4 | impl Node for ContractDefinitionNode {
  5 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
  6 |         match self {
  7 |             ContractDefinitionNode::UsingForDirective(using_for_directive) => {
  8 |                 using_for_directive.accept(visitor)
  9 |             }
 10 |             ContractDefinitionNode::StructDefinition(struct_definition) => {
 11 |                 struct_definition.accept(visitor)
 12 |             }
 13 |             ContractDefinitionNode::EnumDefinition(enum_definition) => {
 14 |                 enum_definition.accept(visitor)
 15 |             }
 16 |             ContractDefinitionNode::VariableDeclaration(variable_declaration) => {
 17 |                 variable_declaration.accept(visitor)
 18 |             }
 19 |             ContractDefinitionNode::EventDefinition(event_definition) => {
 20 |                 event_definition.accept(visitor)
 21 |             }
 22 |             ContractDefinitionNode::FunctionDefinition(function_definition) => {
 23 |                 function_definition.accept(visitor)
 24 |             }
 25 |             ContractDefinitionNode::ModifierDefinition(modifier_definition) => {
 26 |                 modifier_definition.accept(visitor)
 27 |             }
 28 |             ContractDefinitionNode::ErrorDefinition(error_definition) => {
 29 |                 error_definition.accept(visitor)
 30 |             }
 31 |             ContractDefinitionNode::UserDefinedValueTypeDefinition(
 32 |                 user_defined_value_type_definition,
 33 |             ) => user_defined_value_type_definition.accept(visitor),
 34 |         }
 35 |     }
 36 | 
 37 |     fn accept_id(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
 38 |         visitor.visit_node_id(self.get_node_id())?;
 39 |         Ok(())
 40 |     }
 41 | }
 42 | 
 43 | impl Node for InheritanceSpecifier {
 44 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
 45 |         if visitor.visit_inheritance_specifier(self)? {
 46 |             match &self.base_name {
 47 |                 UserDefinedTypeNameOrIdentifierPath::UserDefinedTypeName(type_name) => {
 48 |                     type_name.accept(visitor)?
 49 |                 }
 50 |                 UserDefinedTypeNameOrIdentifierPath::IdentifierPath(identifier_path) => {
 51 |                     identifier_path.accept(visitor)?;
 52 |                 }
 53 |             };
 54 |             if self.arguments.is_some() {
 55 |                 list_accept(self.arguments.as_ref().unwrap(), visitor)?;
 56 |             }
 57 |         }
 58 |         self.accept_metadata(visitor)?;
 59 |         visitor.end_visit_inheritance_specifier(self)
 60 |     }
 61 |     fn accept_metadata(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
 62 |         if let Some(base_name_id) = self.base_name.get_node_id() {
 63 |             visitor.visit_immediate_children(self.id, vec![base_name_id])?;
 64 |         }
 65 |         let mut argument_ids: Vec<NodeID> = vec![];
 66 |         if let Some(arguments) = &self.arguments {
 67 |             for expression in arguments {
 68 |                 let node_id = expression.get_node_id();
 69 |                 if let Some(node_id) = node_id {
 70 |                     argument_ids.push(node_id)
 71 |                 }
 72 |             }
 73 |         }
 74 |         visitor.visit_immediate_children(self.id, argument_ids)?;
 75 |         Ok(())
 76 |     }
 77 |     macros::accept_id!();
 78 | }
 79 | 
 80 | impl Node for ContractDefinition {
 81 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
 82 |         if visitor.visit_contract_definition(self)? {
 83 |             if self.documentation.is_some() {
 84 |                 self.documentation.as_ref().unwrap().accept(visitor)?;
 85 |             }
 86 |             list_accept(&self.base_contracts, visitor)?;
 87 |             list_accept(&self.nodes, visitor)?;
 88 |         }
 89 |         self.accept_metadata(visitor)?;
 90 |         visitor.end_visit_contract_definition(self)
 91 |     }
 92 | 
 93 |     fn accept_metadata(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
 94 |         // TODO: Skipping documentation for now
 95 |         let mut base_contracts_ids = vec![];
 96 |         for base_contract in &self.base_contracts {
 97 |             base_contracts_ids.push(base_contract.id);
 98 |         }
 99 |         visitor.visit_immediate_children(self.id, base_contracts_ids)?;
100 |         let mut node_ids = vec![];
101 |         for node in &self.nodes {
102 |             if let Some(node_id) = node.get_node_id() {
103 |                 node_ids.push(node_id);
104 |             }
105 |         }
106 |         visitor.visit_immediate_children(self.id, node_ids)?;
107 |         Ok(())
108 |     }
109 | 
110 |     macros::accept_id!();
111 | }
112 | 
```

--------------------------------------------------------------------------------
/reports/adhoc-sol-files-highs-only-report.json:
--------------------------------------------------------------------------------

```json
  1 | {
  2 |   "files_summary": {
  3 |     "total_source_units": 20,
  4 |     "total_sloc": 245
  5 |   },
  6 |   "files_details": {
  7 |     "files_details": [
  8 |       {
  9 |         "file_path": "Counter.sol",
 10 |         "n_sloc": 20
 11 |       },
 12 |       {
 13 |         "file_path": "DemoASTNodes.sol",
 14 |         "n_sloc": 31
 15 |       },
 16 |       {
 17 |         "file_path": "Helper.sol",
 18 |         "n_sloc": 8
 19 |       },
 20 |       {
 21 |         "file_path": "InconsistentUints.sol",
 22 |         "n_sloc": 17
 23 |       },
 24 |       {
 25 |         "file_path": "InternalFunctions.sol",
 26 |         "n_sloc": 22
 27 |       },
 28 |       {
 29 |         "file_path": "OnceModifierExample.sol",
 30 |         "n_sloc": 8
 31 |       },
 32 |       {
 33 |         "file_path": "StateVariables.sol",
 34 |         "n_sloc": 58
 35 |       },
 36 |       {
 37 |         "file_path": "inheritance/ExtendedInheritance.sol",
 38 |         "n_sloc": 17
 39 |       },
 40 |       {
 41 |         "file_path": "inheritance/IContractInheritance.sol",
 42 |         "n_sloc": 4
 43 |       },
 44 |       {
 45 |         "file_path": "inheritance/InheritanceBase.sol",
 46 |         "n_sloc": 8
 47 |       },
 48 |       {
 49 |         "file_path": "multiple-versions/0.4/A.sol",
 50 |         "n_sloc": 5
 51 |       },
 52 |       {
 53 |         "file_path": "multiple-versions/0.4/B.sol",
 54 |         "n_sloc": 5
 55 |       },
 56 |       {
 57 |         "file_path": "multiple-versions/0.5/A.sol",
 58 |         "n_sloc": 5
 59 |       },
 60 |       {
 61 |         "file_path": "multiple-versions/0.5/B.sol",
 62 |         "n_sloc": 7
 63 |       },
 64 |       {
 65 |         "file_path": "multiple-versions/0.6/A.sol",
 66 |         "n_sloc": 5
 67 |       },
 68 |       {
 69 |         "file_path": "multiple-versions/0.6/B.sol",
 70 |         "n_sloc": 5
 71 |       },
 72 |       {
 73 |         "file_path": "multiple-versions/0.7/A.sol",
 74 |         "n_sloc": 5
 75 |       },
 76 |       {
 77 |         "file_path": "multiple-versions/0.7/B.sol",
 78 |         "n_sloc": 5
 79 |       },
 80 |       {
 81 |         "file_path": "multiple-versions/0.8/A.sol",
 82 |         "n_sloc": 5
 83 |       },
 84 |       {
 85 |         "file_path": "multiple-versions/0.8/B.sol",
 86 |         "n_sloc": 5
 87 |       }
 88 |     ]
 89 |   },
 90 |   "issue_count": {
 91 |     "high": 2,
 92 |     "low": 0
 93 |   },
 94 |   "high_issues": {
 95 |     "issues": [
 96 |       {
 97 |         "title": "`delegatecall` to an Arbitrary Address",
 98 |         "description": "Making a `delegatecall` to an arbitrary address without any checks is dangerous. Consider adding requirements on the target address.",
 99 |         "detector_name": "delegate-call-unchecked-address",
100 |         "instances": [
101 |           {
102 |             "contract_path": "inheritance/ExtendedInheritance.sol",
103 |             "line_no": 14,
104 |             "src": "391:15",
105 |             "src_char": "391:15"
106 |           }
107 |         ]
108 |       },
109 |       {
110 |         "title": "Unchecked Low level calls",
111 |         "description": "The return value of the low-level call is not checked, so if the call fails, the Ether will be locked in the contract. If the low level is used to prevent blocking operations, consider logging failed calls. Ensure that the return value of a low-level call is checked or logged.",
112 |         "detector_name": "unchecked-low-level-call",
113 |         "instances": [
114 |           {
115 |             "contract_path": "inheritance/ExtendedInheritance.sol",
116 |             "line_no": 16,
117 |             "src": "488:71",
118 |             "src_char": "488:71"
119 |           }
120 |         ]
121 |       }
122 |     ]
123 |   },
124 |   "low_issues": {
125 |     "issues": []
126 |   },
127 |   "detectors_used": [
128 |     "abi-encode-packed-hash-collision",
129 |     "arbitrary-transfer-from",
130 |     "unprotected-initializer",
131 |     "unsafe-casting",
132 |     "enumerable-loop-removal",
133 |     "experimental-encoder",
134 |     "incorrect-shift-order",
135 |     "storage-array-memory-edit",
136 |     "multiple-constructors",
137 |     "reused-contract-name",
138 |     "nested-struct-in-mapping",
139 |     "selfdestruct",
140 |     "dynamic-array-length-assignment",
141 |     "incorrect-caret-operator",
142 |     "yul-return",
143 |     "state-variable-shadowing",
144 |     "unchecked-send",
145 |     "misused-boolean",
146 |     "eth-send-unchecked-address",
147 |     "delegate-call-unchecked-address",
148 |     "tautological-compare",
149 |     "rtlo",
150 |     "dangerous-unary-operator",
151 |     "tautology-or-contradiction",
152 |     "strict-equality-contract-balance",
153 |     "signed-integer-storage-array",
154 |     "weak-randomness",
155 |     "pre-declared-local-variable-usage",
156 |     "delete-nested-mapping",
157 |     "tx-origin-used-for-auth",
158 |     "msg-value-in-loop",
159 |     "contract-locks-ether",
160 |     "incorrect-erc721-interface",
161 |     "incorrect-erc20-interface",
162 |     "out-of-order-retryable",
163 |     "constant-function-changes-state",
164 |     "function-selector-collision",
165 |     "unchecked-low-level-call",
166 |     "reentrancy-state-change"
167 |   ]
168 | }
```
Page 8/103FirstPrevNextLast