#
tokens: 49814/50000 40/1140 files (page 6/103)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 6 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

--------------------------------------------------------------------------------
/tests/ast/documentation_3.json:
--------------------------------------------------------------------------------

```json
1 | {"absolutePath":"c","exportedSymbols":{"C":[23]},"id":24,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":23,"linearizedBaseContracts":[23],"name":"C","nameLocation":"9:1:3","nodeType":"ContractDefinition","nodes":[{"constant":false,"documentation":{"id":7,"nodeType":"StructuredDocumentation","src":"15:32:3","text":"Some comment on state var."},"functionSelector":"c19d93fb","id":9,"mutability":"mutable","name":"state","nameLocation":"60:5:3","nodeType":"VariableDeclaration","scope":23,"src":"48:17:3","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":8,"name":"uint","nodeType":"ElementaryTypeName","src":"48:4:3","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"public"},{"anonymous":false,"documentation":{"id":10,"nodeType":"StructuredDocumentation","src":"69:26:3","text":"Some comment on Evt."},"eventSelector":"a69007916fc1145953e5a7032d7c3eab4b8e2f33ec59b0f71e732904eeede3a4","id":12,"name":"Evt","nameLocation":"102:3:3","nodeType":"EventDefinition","parameters":{"id":11,"nodeType":"ParameterList","parameters":[],"src":"105:2:3"},"src":"96:12:3"},{"body":{"id":16,"nodeType":"Block","src":"153:6:3","statements":[{"id":15,"nodeType":"PlaceholderStatement","src":"155:1:3"}]},"documentation":{"id":13,"nodeType":"StructuredDocumentation","src":"111:26:3","text":"Some comment on mod."},"id":17,"name":"mod","nameLocation":"147:3:3","nodeType":"ModifierDefinition","parameters":{"id":14,"nodeType":"ParameterList","parameters":[],"src":"150:2:3"},"src":"138:21:3","virtual":false,"visibility":"internal"},{"body":{"id":21,"nodeType":"Block","src":"209:2:3","statements":[]},"documentation":{"id":18,"nodeType":"StructuredDocumentation","src":"162:25:3","text":"Some comment on fn."},"functionSelector":"a4a2c40b","id":22,"implemented":true,"kind":"function","modifiers":[],"name":"fn","nameLocation":"197:2:3","nodeType":"FunctionDefinition","parameters":{"id":19,"nodeType":"ParameterList","parameters":[],"src":"199:2:3"},"returnParameters":{"id":20,"nodeType":"ParameterList","parameters":[],"src":"209:0:3"},"scope":23,"src":"188:23:3","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":24,"src":"0:213:3","usedErrors":[]}],"src":"0:214:3"}
2 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/context/graph/callgraph.rs:
--------------------------------------------------------------------------------

```rust
 1 | //! This module helps with strategies on performing different types of investigations.
 2 | //!
 3 | //! Our first kind of callgraph is [`CallGraph`] it comes bundled with actions to help
 4 | //! application modules "hook in" and consume the graphs.
 5 | 
 6 | mod legacy;
 7 | mod new;
 8 | mod tests;
 9 | mod utils;
10 | mod visit;
11 | 
12 | use super::{Error, Result, traits::CallGraphVisitor};
13 | use crate::{
14 |     ast::NodeID,
15 |     context::workspace::{ASTNode, WorkspaceContext},
16 | };
17 | 
18 | #[derive(Clone, PartialEq)]
19 | pub enum CallGraphDirection {
20 |     /// Deeper into the callgraph
21 |     Inward,
22 | 
23 |     /// Opposite of Inward
24 |     Outward,
25 | 
26 |     /// Both inward and outward (If outward side effects also need to be tracked)
27 |     BothWays,
28 | }
29 | 
30 | pub struct CallGraphConsumer {
31 |     /// Ad-hoc Nodes that we would like to explore inward from.
32 |     pub entry_points: Vec<NodeID>,
33 | 
34 |     /// Surface points are calculated based on the entry points (input)
35 |     /// and only consists of [`crate::ast::FunctionDefinition`] and
36 |     /// [`crate::ast::ModifierDefinition`] These are nodes that are the *actual* starting
37 |     /// points for traversal in the graph
38 |     pub inward_surface_points: Vec<NodeID>,
39 | 
40 |     /// Same as the inward one, but acts on reverse graph.
41 |     pub outward_surface_points: Vec<NodeID>,
42 | 
43 |     /// Decides what graph type to chose.
44 |     pub direction: CallGraphDirection,
45 | 
46 |     /// Decides what graph to chose from [`WorkspaceContext::callgraphs`].
47 |     pub base_contract: Option<NodeID>,
48 | }
49 | 
50 | #[derive(PartialEq, Clone, Copy)]
51 | enum CurrentDFSVector {
52 |     Inward,
53 |     Outward,
54 |     OutwardSideEffect,
55 | }
56 | 
57 | impl CallGraphConsumer {
58 |     pub fn get_legacy(
59 |         context: &WorkspaceContext,
60 |         nodes: &[&ASTNode],
61 |         direction: CallGraphDirection,
62 |     ) -> super::Result<CallGraphConsumer> {
63 |         Self::from_nodes(context, nodes, direction)
64 |     }
65 | 
66 |     pub fn get(
67 |         context: &WorkspaceContext,
68 |         nodes: &[&ASTNode],
69 |         direction: CallGraphDirection,
70 |     ) -> super::Result<Vec<CallGraphConsumer>> {
71 |         Self::many_from_nodes(context, nodes, direction)
72 |     }
73 | 
74 |     /// Visit the entry points and all the plausible function definitions and modifier definitions
75 |     /// that EVM may encounter during execution.
76 |     pub fn accept<T>(&self, context: &WorkspaceContext, visitor: &mut T) -> super::Result<()>
77 |     where
78 |         T: CallGraphVisitor,
79 |     {
80 |         self._accept(context, visitor)
81 |     }
82 | 
83 |     #[inline]
84 |     pub fn is_legacy(&self) -> bool {
85 |         self.base_contract.is_none()
86 |     }
87 | }
88 | 
```

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

```rust
 1 | use std::{collections::BTreeMap, error::Error};
 2 | 
 3 | use crate::ast::NodeID;
 4 | 
 5 | use crate::{
 6 |     capture,
 7 |     context::workspace_context::WorkspaceContext,
 8 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 9 | };
10 | use eyre::Result;
11 | 
12 | // HOW TO USE THIS TEMPLATE:
13 | // 1. Copy this file and rename it to the snake_case version of the issue you are detecting.
14 | // 2. Rename the TemplateDetector struct and impl to your new issue name.
15 | // 3. Add this file and detector struct to the mod.rs file in the same directory.
16 | // 4. Implement the detect function to find instances of the issue.
17 | 
18 | #[derive(Default)]
19 | pub struct TemplateDetector {
20 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
21 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
22 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
23 |     hints: BTreeMap<(String, usize, String), String>,
24 | }
25 | 
26 | impl IssueDetector for TemplateDetector {
27 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
28 |         // When you have found an instance of the issue,
29 |         // use the following macro to add it to `found_instances`:
30 |         //
31 |         // capture!(self, context, item);
32 |         // capture!(self, context, item, "hint");
33 | 
34 |         Ok(!self.found_instances.is_empty())
35 |     }
36 | 
37 |     fn severity(&self) -> IssueSeverity {
38 |         IssueSeverity::High
39 |     }
40 | 
41 |     fn title(&self) -> String {
42 |         String::from("High Issue Title")
43 |     }
44 | 
45 |     fn description(&self) -> String {
46 |         String::from("Description of the high issue.")
47 |     }
48 | 
49 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
50 |         self.found_instances.clone()
51 |     }
52 | 
53 |     fn hints(&self) -> BTreeMap<(String, usize, String), String> {
54 |         self.hints.clone()
55 |     }
56 | 
57 |     fn name(&self) -> String {
58 |         format!("high-issue-template")
59 |     }
60 | }
61 | 
62 | #[cfg(test)]
63 | mod template_detector_tests {
64 |     use serial_test::serial;
65 | 
66 |     use crate::detect::{detector::IssueDetector, high::template_detector::TemplateDetector};
67 | 
68 |     #[test]
69 |     fn test_template_detector() {
70 |         let context = crate::detect::test_utils::load_solidity_source_unit(
71 |             "../tests/contract-playground/src/ArbitraryTransferFrom.sol",
72 |         );
73 | 
74 |         let mut detector = TemplateDetector::default();
75 |         let found = detector.detect(&context).unwrap();
76 |         assert!(found);
77 |         assert_eq!(detector.instances().len(), 1);
78 |     }
79 | }
80 | 
```

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

```rust
 1 | use crate::{ast::*, visitor::ast_visitor::*};
 2 | use eyre::Result;
 3 | 
 4 | impl Node for ModifierDefinition {
 5 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
 6 |         if visitor.visit_modifier_definition(self)? {
 7 |             // TODO: should we implement a string based visitor?
 8 |             // self.name.accept(visitor)?;
 9 |             if let Some(body) = &self.body {
10 |                 body.accept(visitor)?;
11 |             }
12 |             if let Some(override_specifier) = &self.overrides {
13 |                 override_specifier.accept(visitor)?;
14 |             }
15 |             self.parameters.accept(visitor)?;
16 |         }
17 |         self.accept_metadata(visitor)?;
18 |         visitor.end_visit_modifier_definition(self)
19 |     }
20 |     fn accept_metadata(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
21 |         if let Some(body) = &self.body {
22 |             visitor.visit_immediate_children(self.id, vec![body.id])?;
23 |         }
24 |         if let Some(override_specifier) = &self.overrides {
25 |             visitor.visit_immediate_children(self.id, vec![override_specifier.id])?;
26 |         }
27 |         visitor.visit_immediate_children(self.id, vec![self.parameters.id])?;
28 |         Ok(())
29 |     }
30 |     macros::accept_id!();
31 | }
32 | 
33 | impl Node for ModifierInvocation {
34 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
35 |         if visitor.visit_modifier_invocation(self)? {
36 |             match &self.modifier_name {
37 |                 IdentifierOrIdentifierPath::Identifier(identifier) => identifier.accept(visitor)?,
38 |                 IdentifierOrIdentifierPath::IdentifierPath(identifier_path) => {
39 |                     identifier_path.accept(visitor)?
40 |                 }
41 |             };
42 |             if self.arguments.is_some() {
43 |                 list_accept(self.arguments.as_ref().unwrap(), visitor)?;
44 |             }
45 |         }
46 |         self.accept_metadata(visitor)?;
47 |         visitor.end_visit_modifier_invocation(self)
48 |     }
49 |     fn accept_metadata(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
50 |         visitor.visit_immediate_children(self.id, vec![self.modifier_name.get_node_id()])?;
51 |         if let Some(arguments) = &self.arguments {
52 |             let mut argument_ids = vec![];
53 |             for arg in arguments {
54 |                 if let Some(arg_id) = arg.get_node_id() {
55 |                     argument_ids.push(arg_id);
56 |                 }
57 |             }
58 |             visitor.visit_immediate_children(self.id, argument_ids)?;
59 |         }
60 |         Ok(())
61 |     }
62 |     macros::accept_id!();
63 | }
64 | 
```

--------------------------------------------------------------------------------
/tests/ast/long_type_name_identifier.json:
--------------------------------------------------------------------------------

```json
1 | {"absolutePath":"a","exportedSymbols":{"c":[15]},"id":16,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"c","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":15,"linearizedBaseContracts":[15],"name":"c","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"constant":false,"id":3,"mutability":"mutable","name":"a","nameLocation":"20:1:1","nodeType":"VariableDeclaration","scope":15,"src":"13:8:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_array$_t_uint256_$dyn_storage","typeString":"uint256[]"},"typeName":{"baseType":{"id":1,"name":"uint","nodeType":"ElementaryTypeName","src":"13:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":2,"nodeType":"ArrayTypeName","src":"13:6:1","typeDescriptions":{"typeIdentifier":"t_array$_t_uint256_$dyn_storage_ptr","typeString":"uint256[]"}},"visibility":"internal"},{"body":{"id":13,"nodeType":"Block","src":"43:25:1","statements":[{"assignments":[10],"declarations":[{"constant":false,"id":10,"mutability":"mutable","name":"b","nameLocation":"60:1:1","nodeType":"VariableDeclaration","scope":13,"src":"45:16:1","stateVariable":false,"storageLocation":"storage","typeDescriptions":{"typeIdentifier":"t_array$_t_uint256_$dyn_storage_ptr","typeString":"uint256[]"},"typeName":{"baseType":{"id":8,"name":"uint","nodeType":"ElementaryTypeName","src":"45:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"id":9,"nodeType":"ArrayTypeName","src":"45:6:1","typeDescriptions":{"typeIdentifier":"t_array$_t_uint256_$dyn_storage_ptr","typeString":"uint256[]"}},"visibility":"internal"}],"id":12,"initialValue":{"id":11,"name":"a","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":3,"src":"64:1:1","typeDescriptions":{"typeIdentifier":"t_array$_t_uint256_$dyn_storage","typeString":"uint256[] storage ref"}},"nodeType":"VariableDeclarationStatement","src":"45:20:1"}]},"functionSelector":"26121ff0","id":14,"implemented":true,"kind":"function","modifiers":[],"name":"f","nameLocation":"32:1:1","nodeType":"FunctionDefinition","parameters":{"id":4,"nodeType":"ParameterList","parameters":[],"src":"33:2:1"},"returnParameters":{"id":5,"nodeType":"ParameterList","parameters":[],"src":"43:0:1"},"scope":15,"src":"23:45:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":16,"src":"0:70:1","usedErrors":[]}],"src":"0:71:1"}
2 | 
```

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

```rust
 1 | use std::collections::BTreeMap;
 2 | use std::error::Error;
 3 | 
 4 | use crate::ast::NodeID;
 5 | 
 6 | use crate::capture;
 7 | use crate::detect::detector::IssueDetectorNamePool;
 8 | use crate::{
 9 |     context::workspace_context::WorkspaceContext,
10 |     detect::detector::{IssueDetector, IssueSeverity},
11 | };
12 | use eyre::Result;
13 | 
14 | // HOW TO USE THIS TEMPLATE:
15 | // 1. Copy this file and rename it to the snake_case version of the issue you are detecting.
16 | // 2. Rename the TemplateDetector struct and impl to your new issue name.
17 | // 3. Add this file and detector struct to the mod.rs file in the same directory.
18 | // 4. Implement the detect function to find instances of the issue.
19 | 
20 | #[derive(Default)]
21 | pub struct TemplateDetector {
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 |     hints: BTreeMap<(String, usize, String), String>,
26 | }
27 | 
28 | impl IssueDetector for TemplateDetector {
29 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
30 |         // When you have found an instance of the issue,
31 |         // use the following macro to add it to `found_instances`:
32 |         //
33 |         // capture!(self, context, item);
34 |         // capture!(self, context, item, "hint");
35 | 
36 |         Ok(!self.found_instances.is_empty())
37 |     }
38 | 
39 |     fn severity(&self) -> IssueSeverity {
40 |         IssueSeverity::Low
41 |     }
42 | 
43 |     fn title(&self) -> String {
44 |         String::from("Low Issue Title")
45 |     }
46 | 
47 |     fn description(&self) -> String {
48 |         String::from("Description of the low issue.")
49 |     }
50 | 
51 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
52 |         self.found_instances.clone()
53 |     }
54 | 
55 |     fn hints(&self) -> BTreeMap<(String, usize, String), String> {
56 |         self.hints.clone()
57 |     }
58 | 
59 |     fn name(&self) -> String {
60 |         format!("low-issue-template")
61 |     }
62 | }
63 | 
64 | #[cfg(test)]
65 | mod template_detector_tests {
66 |     use serial_test::serial;
67 | 
68 |     use crate::detect::{detector::IssueDetector, low::template_detector::TemplateDetector};
69 | 
70 |     #[test]
71 |     fn test_template_detector() {
72 |         let context = crate::detect::test_utils::load_solidity_source_unit(
73 |             "../tests/contract-playground/src/ArbitraryTransferFrom.sol",
74 |         );
75 | 
76 |         let mut detector = TemplateDetector::default();
77 |         let found = detector.detect(&context).unwrap();
78 |         assert!(found);
79 |         assert_eq!(detector.instances().len(), 1);
80 |     }
81 | }
82 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/unsafe_erc20_operation.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 UnsafeERC20OperationDetector {
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 UnsafeERC20OperationDetector {
19 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
20 |         for member_access in context.member_accesses() {
21 |             if member_access.expression.as_ref().type_descriptions().is_some_and(|desc| {
22 |                 desc.type_string.as_ref().is_some_and(|type_string| type_string.contains("ERC20"))
23 |             }) && member_access.member_name == "transferFrom"
24 |                 || member_access.member_name == "approve"
25 |                 || member_access.member_name == "transfer"
26 |             {
27 |                 capture!(self, context, member_access);
28 |             }
29 |         }
30 |         Ok(!self.found_instances.is_empty())
31 |     }
32 | 
33 |     fn title(&self) -> String {
34 |         String::from("Unsafe ERC20 Operation")
35 |     }
36 | 
37 |     fn description(&self) -> String {
38 |         String::from(
39 |             "ERC20 functions may not behave as expected. For example: return values are not always meaningful. It is recommended to use OpenZeppelin's SafeERC20 library.",
40 |         )
41 |     }
42 | 
43 |     fn severity(&self) -> IssueSeverity {
44 |         IssueSeverity::Low
45 |     }
46 | 
47 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
48 |         self.found_instances.clone()
49 |     }
50 | 
51 |     fn name(&self) -> String {
52 |         format!("{}", IssueDetectorNamePool::UnsafeERC20Operation)
53 |     }
54 | }
55 | 
56 | #[cfg(test)]
57 | mod unsafe_erc20_functions_tests {
58 |     use crate::detect::detector::IssueDetector;
59 | 
60 |     use super::UnsafeERC20OperationDetector;
61 | 
62 |     #[test]
63 | 
64 |     fn test_unsafe_erc20_functions_by_loading_contract_directly() {
65 |         let context = crate::detect::test_utils::load_solidity_source_unit(
66 |             "../tests/contract-playground/src/DeprecatedOZFunctions.sol",
67 |         );
68 | 
69 |         let mut detector = UnsafeERC20OperationDetector::default();
70 |         let found = detector.detect(&context).unwrap();
71 |         assert!(found);
72 |         // failure0, failure1 and failure3
73 |         assert_eq!(detector.instances().len(), 5);
74 |     }
75 | }
76 | 
```

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

```rust
 1 | use std::{collections::BTreeMap, error::Error};
 2 | 
 3 | use crate::{
 4 |     ast::{NodeID, Visibility},
 5 |     capture,
 6 |     context::workspace::WorkspaceContext,
 7 |     detect::{
 8 |         detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 9 |         helpers::count_identifiers_that_reference_an_id,
10 |     },
11 | };
12 | use eyre::Result;
13 | 
14 | #[derive(Default)]
15 | pub struct InternalFunctionUsedOnceDetector {
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 InternalFunctionUsedOnceDetector {
22 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
23 |         let internal_functions = context.function_definitions().into_iter().filter(|&function| {
24 |             matches!(function.visibility, Visibility::Internal) && !function.name.starts_with('_')
25 |         });
26 | 
27 |         for internal_function in internal_functions {
28 |             if count_identifiers_that_reference_an_id(context, internal_function.id) == 1 {
29 |                 capture!(self, context, internal_function);
30 |             }
31 |         }
32 | 
33 |         Ok(!self.found_instances.is_empty())
34 |     }
35 | 
36 |     fn title(&self) -> String {
37 |         String::from("Internal Function Used Only Once")
38 |     }
39 | 
40 |     fn description(&self) -> String {
41 |         String::from(
42 |             "Instead of separating the logic into a separate function, consider inlining the logic into the calling function. This can reduce the number of function calls and improve readability.",
43 |         )
44 |     }
45 | 
46 |     fn severity(&self) -> IssueSeverity {
47 |         IssueSeverity::Low
48 |     }
49 | 
50 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
51 |         self.found_instances.clone()
52 |     }
53 | 
54 |     fn name(&self) -> String {
55 |         format!("{}", IssueDetectorNamePool::InternalFunctionUsedOnce)
56 |     }
57 | }
58 | 
59 | #[cfg(test)]
60 | mod uselss_internal_function {
61 |     use crate::detect::detector::IssueDetector;
62 | 
63 |     use super::InternalFunctionUsedOnceDetector;
64 | 
65 |     #[test]
66 | 
67 |     fn test_useless_internal_functions_by_loading_contract_directly() {
68 |         let context = crate::detect::test_utils::load_solidity_source_unit(
69 |             "../tests/contract-playground/src/InternalFunctions.sol",
70 |         );
71 | 
72 |         let mut detector = InternalFunctionUsedOnceDetector::default();
73 |         let found = detector.detect(&context).unwrap();
74 |         assert!(found);
75 |         assert_eq!(detector.instances().len(), 1);
76 |     }
77 | }
78 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/non_reentrant_not_first.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 NonReentrantBeforeOthersDetector {
13 |     // Keys are source file name, line number and source location
14 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
15 | }
16 | 
17 | impl IssueDetector for NonReentrantBeforeOthersDetector {
18 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
19 |         let function_definitions = context.function_definitions();
20 |         for definition in function_definitions {
21 |             if definition.modifiers.len() > 1 {
22 |                 for (index, modifier) in definition.modifiers.iter().enumerate() {
23 |                     if modifier.modifier_name.name().to_lowercase().contains("nonreentrant")
24 |                         && index != 0
25 |                     {
26 |                         capture!(self, context, modifier);
27 |                     }
28 |                 }
29 |             }
30 |         }
31 |         Ok(!self.found_instances.is_empty())
32 |     }
33 | 
34 |     fn title(&self) -> String {
35 |         String::from("`nonReentrant` is Not the First Modifier")
36 |     }
37 | 
38 |     fn description(&self) -> String {
39 |         String::from(
40 |             "To protect against reentrancy in other modifiers, the `nonReentrant` modifier should be the first modifier in the list of modifiers.",
41 |         )
42 |     }
43 | 
44 |     fn severity(&self) -> IssueSeverity {
45 |         IssueSeverity::Low
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::NonReentrantNotFirst)
54 |     }
55 | }
56 | 
57 | #[cfg(test)]
58 | mod non_reentrant_before_others_tests {
59 | 
60 |     use crate::detect::{detector::IssueDetector, low::NonReentrantBeforeOthersDetector};
61 | 
62 |     #[test]
63 | 
64 |     fn test_non_reentrant_before_others_by_loading_contract_directly() {
65 |         let context = crate::detect::test_utils::load_solidity_source_unit(
66 |             "../tests/contract-playground/src/AdminContract.sol",
67 |         );
68 | 
69 |         let mut detector = NonReentrantBeforeOthersDetector::default();
70 |         let found = detector.detect(&context).unwrap();
71 |         assert!(found);
72 |         assert_eq!(detector.instances().len(), 1);
73 | 
74 |         // assert that the line number is 10
75 |         let (_, line_number, _) = detector.instances().keys().next().unwrap().clone();
76 |         assert_eq!(line_number, 10);
77 |     }
78 | }
79 | 
```

--------------------------------------------------------------------------------
/tests/ast/mutability.json:
--------------------------------------------------------------------------------

```json
1 | {"absolutePath":"a","exportedSymbols":{"C":[10]},"id":11,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":10,"linearizedBaseContracts":[10],"name":"C","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"constant":false,"functionSelector":"0dbe671f","id":3,"mutability":"immutable","name":"a","nameLocation":"39:1:1","nodeType":"VariableDeclaration","scope":10,"src":"17:27:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1,"name":"uint","nodeType":"ElementaryTypeName","src":"17:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":{"hexValue":"34","id":2,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"43:1:1","typeDescriptions":{"typeIdentifier":"t_rational_4_by_1","typeString":"int_const 4"},"value":"4"},"visibility":"public"},{"constant":true,"functionSelector":"4df7e3d0","id":6,"mutability":"constant","name":"b","nameLocation":"71:1:1","nodeType":"VariableDeclaration","scope":10,"src":"50:26:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":4,"name":"uint","nodeType":"ElementaryTypeName","src":"50:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":{"hexValue":"32","id":5,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"75:1:1","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"},"visibility":"public"},{"constant":false,"functionSelector":"c3da42b8","id":9,"mutability":"mutable","name":"c","nameLocation":"94:1:1","nodeType":"VariableDeclaration","scope":10,"src":"82:17:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":7,"name":"uint","nodeType":"ElementaryTypeName","src":"82:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"value":{"hexValue":"33","id":8,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"98:1:1","typeDescriptions":{"typeIdentifier":"t_rational_3_by_1","typeString":"int_const 3"},"value":"3"},"visibility":"public"}],"scope":11,"src":"0:102:1","usedErrors":[]}],"src":"0:103:1"}
2 | 
```

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

```rust
 1 | use crate::{ast::*, visitor::ast_visitor::*};
 2 | use eyre::Result;
 3 | use macros::accept_id;
 4 | 
 5 | impl Node for TypeName {
 6 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
 7 |         match self {
 8 |             TypeName::FunctionTypeName(function_type_name) => function_type_name.accept(visitor),
 9 |             TypeName::ArrayTypeName(array_type_name) => array_type_name.accept(visitor),
10 |             TypeName::Mapping(mapping) => mapping.accept(visitor),
11 |             TypeName::UserDefinedTypeName(user_defined_type_name) => {
12 |                 user_defined_type_name.accept(visitor)
13 |             }
14 |             TypeName::ElementaryTypeName(elementary_type_name) => {
15 |                 elementary_type_name.accept(visitor)
16 |             }
17 |             TypeName::Raw(_) => Ok(()),
18 |         }
19 |     }
20 |     fn accept_id(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
21 |         visitor.visit_node_id(self.get_node_id())?;
22 |         Ok(())
23 |     }
24 | }
25 | 
26 | impl Node for ElementaryTypeName {
27 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
28 |         visitor.visit_elementary_type_name(self)?;
29 |         visitor.end_visit_elementary_type_name(self)
30 |     }
31 |     accept_id!();
32 | }
33 | 
34 | impl Node for UserDefinedTypeName {
35 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
36 |         if visitor.visit_user_defined_type_name(self)? && self.path_node.is_some() {
37 |             self.path_node.as_ref().unwrap().accept(visitor)?;
38 |         }
39 |         visitor.end_visit_user_defined_type_name(self)
40 |     }
41 |     accept_id!();
42 | }
43 | 
44 | impl Node for FunctionTypeName {
45 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
46 |         if visitor.visit_function_type_name(self)? {
47 |             self.parameter_types.accept(visitor)?;
48 |             self.return_parameter_types.accept(visitor)?;
49 |         }
50 |         visitor.end_visit_function_type_name(self)
51 |     }
52 |     accept_id!();
53 | }
54 | 
55 | impl Node for ArrayTypeName {
56 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
57 |         if visitor.visit_array_type_name(self)? {
58 |             self.base_type.accept(visitor)?;
59 |             if let Some(length) = self.length.as_ref() {
60 |                 length.accept(visitor)?;
61 |             }
62 |         }
63 |         visitor.end_visit_array_type_name(self)
64 |     }
65 |     accept_id!();
66 | }
67 | 
68 | impl Node for Mapping {
69 |     fn accept(&self, visitor: &mut impl ASTConstVisitor) -> Result<()> {
70 |         if visitor.visit_mapping(self)? {
71 |             self.key_type.accept(visitor)?;
72 |             self.value_type.accept(visitor)?;
73 |         }
74 |         visitor.end_visit_mapping(self)
75 |     }
76 |     accept_id!();
77 | }
78 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/context/flow/kind.rs:
--------------------------------------------------------------------------------

```rust
 1 | //! Following are the types of statements that are to be considered when building a
 2 | //! Control Flow graph
 3 | //!
 4 | //! REDUCIBLES
 5 | //!
 6 | //! Step-in
 7 | //! -------
 8 | //! Block
 9 | //! UncheckedBlock
10 | //!
11 | //! Flow
12 | //! ----
13 | //! DoWhileStatement
14 | //! IfStatement
15 | //! ForStatement
16 | //! WhileStatement
17 | //!
18 | //! ----------------------------
19 | //!
20 | //! PRIMITIVES
21 | //!
22 | //! Substitute
23 | //! ----------
24 | //! PlaceholderStatement
25 | //!
26 | //! Jumper
27 | //! ------
28 | //! Break
29 | //! Continue
30 | //! Return
31 | //!
32 | //! Regular
33 | //! ------
34 | //! EmitStatement
35 | //! RevertStatement
36 | //! ExpressionStatement
37 | //! InlineAssembly
38 | //! VariableDeclarationStatement
39 | //! TryStatement
40 | 
41 | use super::CfgNodeDescriptor;
42 | 
43 | #[derive(PartialEq, Clone, Copy)]
44 | pub enum CfgNodeKind {
45 |     Void,
46 |     Reducible,
47 |     Primitive,
48 | }
49 | 
50 | impl CfgNodeDescriptor {
51 |     pub fn kind(&self) -> CfgNodeKind {
52 |         match self {
53 |             // Void nodes
54 |             CfgNodeDescriptor::Start(_) => CfgNodeKind::Void,
55 |             CfgNodeDescriptor::End(_) => CfgNodeKind::Void,
56 | 
57 |             // Primitives
58 |             CfgNodeDescriptor::VariableDeclarationStatement(_) => CfgNodeKind::Primitive,
59 |             CfgNodeDescriptor::ExpressionStatement(_) => CfgNodeKind::Primitive,
60 |             CfgNodeDescriptor::PlaceholderStatement(_) => CfgNodeKind::Primitive,
61 |             CfgNodeDescriptor::Break(_) => CfgNodeKind::Primitive,
62 |             CfgNodeDescriptor::Continue(_) => CfgNodeKind::Primitive,
63 |             CfgNodeDescriptor::Return(_) => CfgNodeKind::Primitive,
64 |             CfgNodeDescriptor::EmitStatement(_) => CfgNodeKind::Primitive,
65 |             CfgNodeDescriptor::RevertStatement(_) => CfgNodeKind::Primitive,
66 |             CfgNodeDescriptor::InlineAssembly(_) => CfgNodeKind::Primitive,
67 |             CfgNodeDescriptor::TryStatement(_) => CfgNodeKind::Primitive,
68 |             CfgNodeDescriptor::IfStatementCondition(_) => CfgNodeKind::Primitive,
69 |             CfgNodeDescriptor::WhileStatementCondition(_) => CfgNodeKind::Primitive,
70 |             CfgNodeDescriptor::ForStatementCondition(_) => CfgNodeKind::Primitive,
71 |             CfgNodeDescriptor::DoWhileStatementCondition(_) => CfgNodeKind::Primitive,
72 | 
73 |             // Reducibles
74 |             CfgNodeDescriptor::Block(_) => CfgNodeKind::Reducible,
75 |             CfgNodeDescriptor::UncheckedBlock(_) => CfgNodeKind::Reducible,
76 |             CfgNodeDescriptor::IfStatement(_) => CfgNodeKind::Reducible,
77 |             CfgNodeDescriptor::WhileStatement(_) => CfgNodeKind::Reducible,
78 |             CfgNodeDescriptor::ForStatement(_) => CfgNodeKind::Reducible,
79 |             CfgNodeDescriptor::DoWhileStatement(_) => CfgNodeKind::Reducible,
80 |         }
81 |     }
82 | }
83 | 
```

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

```rust
 1 | use std::{collections::BTreeMap, error::Error};
 2 | 
 3 | use crate::{
 4 |     ast::{LiteralKind, 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 LargeLiteralValueDetector {
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 LargeLiteralValueDetector {
19 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
20 |         for numeric_literal in context.literals().iter().filter(|x| x.kind == LiteralKind::Number) {
21 |             if let Some(value) = numeric_literal.value.clone() {
22 |                 // Strip any underscore separators
23 |                 let value_no_underscores = value.replace('_', "");
24 |                 let is_huge = value_no_underscores.ends_with("0000");
25 |                 let is_hex = value_no_underscores.starts_with("0x");
26 |                 let is_exp = value_no_underscores.contains('e');
27 |                 if is_huge && !is_hex && !is_exp {
28 |                     capture!(self, context, numeric_literal);
29 |                 }
30 |             }
31 |         }
32 | 
33 |         Ok(!self.found_instances.is_empty())
34 |     }
35 | 
36 |     fn title(&self) -> String {
37 |         String::from("Large Numeric Literal")
38 |     }
39 | 
40 |     fn description(&self) -> String {
41 |         String::from(
42 |             "Large literal values multiples of 10000 can be replaced with scientific notation.Use `e` notation, for example: `1e18`, instead of its full numeric value.",
43 |         )
44 |     }
45 | 
46 |     fn severity(&self) -> IssueSeverity {
47 |         IssueSeverity::Low
48 |     }
49 | 
50 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
51 |         self.found_instances.clone()
52 |     }
53 | 
54 |     fn name(&self) -> String {
55 |         format!("{}", IssueDetectorNamePool::LargeNumericLiteral)
56 |     }
57 | }
58 | 
59 | #[cfg(test)]
60 | mod large_literal_values {
61 | 
62 |     use crate::detect::detector::IssueDetector;
63 | 
64 |     use super::LargeLiteralValueDetector;
65 | 
66 |     #[test]
67 | 
68 |     fn test_large_literal_values_multiples_of_10000_by_loading_contract_directly() {
69 |         let context = crate::detect::test_utils::load_solidity_source_unit(
70 |             "../tests/contract-playground/src/HugeConstants.sol",
71 |         );
72 | 
73 |         let mut detector = LargeLiteralValueDetector::default();
74 |         let found = detector.detect(&context).unwrap();
75 |         assert!(found);
76 |         assert_eq!(detector.instances().len(), 22);
77 |     }
78 | }
79 | 
```

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

```rust
 1 | use crate::{
 2 |     ast::NodeID,
 3 |     capture,
 4 |     context::workspace::WorkspaceContext,
 5 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 6 | };
 7 | use eyre::Result;
 8 | use std::{
 9 |     collections::{BTreeMap, HashSet},
10 |     error::Error,
11 | };
12 | 
13 | #[derive(Default)]
14 | pub struct UnusedErrorDetector {
15 |     // Keys are source file name and line number
16 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
17 | }
18 | 
19 | impl IssueDetector for UnusedErrorDetector {
20 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
21 |         let error_definitions = context.error_definitions().into_iter().collect::<Vec<_>>();
22 |         let mut referenced_ids = HashSet::new();
23 | 
24 |         //Get all MemberAccess and Identifier nodes where the referenced_declaration is an ID of an
25 |         // error definition
26 |         for identifier in context.identifiers() {
27 |             if let Some(reference_id) = identifier.referenced_declaration {
28 |                 referenced_ids.insert(reference_id);
29 |             }
30 |         }
31 |         for member_access in context.member_accesses() {
32 |             if let Some(reference_id) = member_access.referenced_declaration {
33 |                 referenced_ids.insert(reference_id);
34 |             }
35 |         }
36 | 
37 |         // Identify unused errors by comparing defined and used error IDs
38 |         for error_def in error_definitions {
39 |             if !referenced_ids.contains(&error_def.id) {
40 |                 // Capture unused error instances
41 |                 capture!(self, context, error_def);
42 |             }
43 |         }
44 |         Ok(!self.found_instances.is_empty())
45 |     }
46 | 
47 |     fn title(&self) -> String {
48 |         String::from("Unused Error")
49 |     }
50 | 
51 |     fn description(&self) -> String {
52 |         String::from("Consider using or removing the unused error.")
53 |     }
54 | 
55 |     fn severity(&self) -> IssueSeverity {
56 |         IssueSeverity::Low
57 |     }
58 | 
59 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
60 |         self.found_instances.clone()
61 |     }
62 | 
63 |     fn name(&self) -> String {
64 |         format!("{}", IssueDetectorNamePool::UnusedError)
65 |     }
66 | }
67 | 
68 | #[cfg(test)]
69 | mod unused_error_tests {
70 | 
71 |     use crate::detect::detector::IssueDetector;
72 | 
73 |     use super::UnusedErrorDetector;
74 | 
75 |     #[test]
76 | 
77 |     fn test_unused_error_detection() {
78 |         let context = crate::detect::test_utils::load_solidity_source_unit(
79 |             "../tests/contract-playground/src/UnusedError.sol",
80 |         );
81 | 
82 |         let mut detector = UnusedErrorDetector::default();
83 |         let found = detector.detect(&context).unwrap();
84 |         assert!(found);
85 |         assert_eq!(detector.instances().len(), 2);
86 |     }
87 | }
88 | 
```

--------------------------------------------------------------------------------
/aderyn/templates/aderyn.toml:
--------------------------------------------------------------------------------

```toml
 1 | # Aderyn Configuration File
 2 | # Help Aderyn work with more granular control
 3 | 
 4 | # DO NOT CHANGE version below. As of now, only 1 is supported
 5 | version = 1
 6 | 
 7 | # Read the description carefully and uncomment the examples in each paragraph should you consider using them.
 8 | 
 9 | # Base path for resolving remappings and compiling smart contracts, relative to workspace-root (directory in which the editor is open)
10 | # Most of the time, you want to point it to the directory containing foundry.toml or hardhat.config.js/ts.
11 | root = {}
12 | 
13 | # Path of source directory containing the contracts, relative to root (above)
14 | # Aderyn will traverse all the nested files inside to scan and report vulnerabilities found inside.
15 | # - If not specified, Aderyn will try to extract it from the framework that is being used. (Foundry / Hardhat). 
16 | #   That would be "contracts/" in case of Hardhat and in case of Foundry, it depends on foundry.toml and
17 | #   many other factors like FOUNDRY_PROFILE environment variable, etc.
18 | # - If specified, Aderyn will override the above found `src`.
19 | # Example:
20 | # src = "src/"
21 | 
22 | # Path segments of contract files to include in the analysis.
23 | # - It can be a partial match like "/interfaces/", which will include all files with "/interfaces/" in the file path.
24 | #   Or it can be a full match like "src/counters/Counter.sol", which will include only the file with the exact path.
25 | # - If not specified, all contract files in the source directory will be included.
26 | # Examples:
27 | # include = ["src/counters/Counter.sol", "src/others/"]
28 | # include = ["/interfaces/"]
29 | 
30 | # Path segments of contract files to exclude in the analysis.
31 | # - It can be a partial match like "/interfaces/", which will exclude all files with "/interfaces/" in the file path.
32 | #   Or it can be a full match like "src/counters/Counter.sol", which will exclude only the file with the exact path.
33 | # - If not specified, no contract files will be excluded.
34 | # Examples:
35 | # exclude = ["src/counters/Counter.sol", "src/others/"]
36 | # exclude = ["/interfaces/"]
37 | 
38 | # For advanced use cases, leverage the following
39 | 
40 | # Remappings 
41 | # - It can be specified in `remappings.txt` within the root folder of the project.
42 | # - If not specified, Aderyn will try to derive the values from foundry.toml (if present.)
43 | 
44 | # Environment
45 | # - These are usually all the FOUNDRY_, DAPP_ environment variables that are used during development.
46 | # - For example, if different profiles have different `src` declaration in `foundry.toml`, FOUNDRY_PROFILE can dictate the correct `src` value.
47 | #   Env variables and their values can be specified below.
48 | 
49 | [env]
50 | # Example:
51 | # FOUNDRY_PROFILE = "default"
52 | 
```

--------------------------------------------------------------------------------
/tests/toml/nested_project1/aderyn.toml:
--------------------------------------------------------------------------------

```toml
 1 | # Aderyn Configuration File
 2 | # Help Aderyn work with more granular control
 3 | 
 4 | # DO NOT CHANGE version below. As of now, only 1 is supported
 5 | version = 1
 6 | 
 7 | # Read the description carefully and uncomment the examples in each paragraph should you consider using them.
 8 | 
 9 | # Base path for resolving remappings and compiling smart contracts, relative to workspace-root (directory in which the editor is open)
10 | # Most of the time, you want to point it to the directory containing foundry.toml or hardhat.config.js/ts.
11 | root = "folder2"
12 | 
13 | # Path of source directory containing the contracts, relative to root (above)
14 | # Aderyn will traverse all the nested files inside to scan and report vulnerabilities found inside.
15 | # - If not specified, Aderyn will try to extract it from the framework that is being used. (Foundry / Hardhat). 
16 | #   That would be "contracts/" in case of Hardhat and in case of Foundry, it depends on foundry.toml and
17 | #   many other factors like FOUNDRY_PROFILE environment variable, etc.
18 | # - If specified, Aderyn will override the above found `src`.
19 | # Example:
20 | # src = "src/"
21 | 
22 | # Path segments of contract files to include in the analysis.
23 | # - It can be a partial match like "/interfaces/", which will include all files with "/interfaces/" in the file path.
24 | #   Or it can be a full match like "src/counters/Counter.sol", which will include only the file with the exact path.
25 | # - If not specified, all contract files in the source directory will be included.
26 | # Examples:
27 | # include = ["src/counters/Counter.sol", "src/others/"]
28 | # include = ["/interfaces/"]
29 | 
30 | # Path segments of contract files to exclude in the analysis.
31 | # - It can be a partial match like "/interfaces/", which will exclude all files with "/interfaces/" in the file path.
32 | #   Or it can be a full match like "src/counters/Counter.sol", which will exclude only the file with the exact path.
33 | # - If not specified, no contract files will be excluded.
34 | # Examples:
35 | # exclude = ["src/counters/Counter.sol", "src/others/"]
36 | # exclude = ["/interfaces/"]
37 | 
38 | # For advanced use cases, leverage the following
39 | 
40 | # Remappings 
41 | # - It can be specified in `remappings.txt` within the root folder of the project.
42 | # - If not specified, Aderyn will try to derive the values from foundry.toml (if present.)
43 | 
44 | # Environment
45 | # - These are usually all the FOUNDRY_, DAPP_ environment variables that are used during development.
46 | # - For example, if different profiles have different `src` declaration in `foundry.toml`, FOUNDRY_PROFILE can dictate the correct `src` value.
47 | #   Env variables and their values can be specified below.
48 | 
49 | [env]
50 | # Example:
51 | # FOUNDRY_PROFILE = "default"
52 | 
```

--------------------------------------------------------------------------------
/tests/toml/nested_project2/aderyn.toml:
--------------------------------------------------------------------------------

```toml
 1 | # Aderyn Configuration File
 2 | # Help Aderyn work with more granular control
 3 | 
 4 | # DO NOT CHANGE version below. As of now, only 1 is supported
 5 | version = 1
 6 | 
 7 | # Read the description carefully and uncomment the examples in each paragraph should you consider using them.
 8 | 
 9 | # Base path for resolving remappings and compiling smart contracts, relative to workspace-root (directory in which the editor is open)
10 | # Most of the time, you want to point it to the directory containing foundry.toml or hardhat.config.js/ts.
11 | root = "folder1"
12 | 
13 | # Path of source directory containing the contracts, relative to root (above)
14 | # Aderyn will traverse all the nested files inside to scan and report vulnerabilities found inside.
15 | # - If not specified, Aderyn will try to extract it from the framework that is being used. (Foundry / Hardhat). 
16 | #   That would be "contracts/" in case of Hardhat and in case of Foundry, it depends on foundry.toml and
17 | #   many other factors like FOUNDRY_PROFILE environment variable, etc.
18 | # - If specified, Aderyn will override the above found `src`.
19 | # Example:
20 | # src = "src/"
21 | 
22 | # Path segments of contract files to include in the analysis.
23 | # - It can be a partial match like "/interfaces/", which will include all files with "/interfaces/" in the file path.
24 | #   Or it can be a full match like "src/counters/Counter.sol", which will include only the file with the exact path.
25 | # - If not specified, all contract files in the source directory will be included.
26 | # Examples:
27 | # include = ["src/counters/Counter.sol", "src/others/"]
28 | # include = ["/interfaces/"]
29 | 
30 | # Path segments of contract files to exclude in the analysis.
31 | # - It can be a partial match like "/interfaces/", which will exclude all files with "/interfaces/" in the file path.
32 | #   Or it can be a full match like "src/counters/Counter.sol", which will exclude only the file with the exact path.
33 | # - If not specified, no contract files will be excluded.
34 | # Examples:
35 | # exclude = ["src/counters/Counter.sol", "src/others/"]
36 | # exclude = ["/interfaces/"]
37 | 
38 | # For advanced use cases, leverage the following
39 | 
40 | # Remappings 
41 | # - It can be specified in `remappings.txt` within the root folder of the project.
42 | # - If not specified, Aderyn will try to derive the values from foundry.toml (if present.)
43 | 
44 | # Environment
45 | # - These are usually all the FOUNDRY_, DAPP_ environment variables that are used during development.
46 | # - For example, if different profiles have different `src` declaration in `foundry.toml`, FOUNDRY_PROFILE can dictate the correct `src` value.
47 | #   Env variables and their values can be specified below.
48 | 
49 | [env]
50 | # Example:
51 | # FOUNDRY_PROFILE = "default"
52 | 
```

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

```rust
 1 | use std::{
 2 |     collections::{BTreeMap, HashMap},
 3 |     error::Error,
 4 | };
 5 | 
 6 | use crate::{
 7 |     ast::NodeID,
 8 |     capture,
 9 |     context::workspace::WorkspaceContext,
10 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
11 | };
12 | use eyre::Result;
13 | 
14 | #[derive(Default)]
15 | pub struct ModifierUsedOnlyOnceDetector {
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 ModifierUsedOnlyOnceDetector {
22 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
23 |         let mut invocations: HashMap<i64, usize> = HashMap::new();
24 | 
25 |         for inv in context.modifier_invocations() {
26 |             if let Some(id) = inv.modifier_name.referenced_declaration() {
27 |                 match invocations.entry(id) {
28 |                     std::collections::hash_map::Entry::Occupied(mut o) => *o.get_mut() += 1,
29 |                     std::collections::hash_map::Entry::Vacant(v) => {
30 |                         v.insert(1);
31 |                     }
32 |                 };
33 |             }
34 |         }
35 | 
36 |         for modifier in context.modifier_definitions() {
37 |             let count = *invocations.get(&modifier.id).unwrap_or(&0);
38 |             if count == 1 {
39 |                 capture!(self, context, modifier);
40 |             }
41 |         }
42 | 
43 |         Ok(!self.found_instances.is_empty())
44 |     }
45 | 
46 |     fn title(&self) -> String {
47 |         String::from("Modifier Invoked Only Once")
48 |     }
49 | 
50 |     fn description(&self) -> String {
51 |         String::from(
52 |             "Consider removing the modifier or inlining the logic into the calling function.",
53 |         )
54 |     }
55 | 
56 |     fn severity(&self) -> IssueSeverity {
57 |         IssueSeverity::Low
58 |     }
59 | 
60 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
61 |         self.found_instances.clone()
62 |     }
63 | 
64 |     fn name(&self) -> String {
65 |         format!("{}", IssueDetectorNamePool::ModifierUsedOnlyOnce)
66 |     }
67 | }
68 | 
69 | #[cfg(test)]
70 | mod useless_modifier_tests {
71 |     use crate::detect::detector::IssueDetector;
72 | 
73 |     use super::ModifierUsedOnlyOnceDetector;
74 | 
75 |     #[test]
76 | 
77 |     fn test_useless_modifier_tests_by_loading_contract_directly() {
78 |         let context = crate::detect::test_utils::load_solidity_source_unit(
79 |             "../tests/contract-playground/src/OnceModifierExample.sol",
80 |         );
81 | 
82 |         let mut detector = ModifierUsedOnlyOnceDetector::default();
83 |         let found = detector.detect(&context).unwrap();
84 |         assert!(found);
85 |         assert_eq!(detector.instances().len(), 1);
86 |     }
87 | }
88 | 
```

--------------------------------------------------------------------------------
/aderyn_driver/src/mcp.rs:
--------------------------------------------------------------------------------

```rust
 1 | use crate::process::WorkspaceContextWrapper;
 2 | 
 3 | use aderyn_core::context::mcp::*;
 4 | use rmcp::{
 5 |     ErrorData as McpError, RoleServer, ServerHandler, handler::server::router::tool::ToolRouter,
 6 |     model::*, service::RequestContext, tool_handler,
 7 | };
 8 | use std::sync::Arc;
 9 | 
10 | pub struct McpServer {
11 |     tool_router: ToolRouter<Self>,
12 | }
13 | 
14 | impl McpServer {
15 |     pub fn new(raw_state: WorkspaceContextWrapper) -> Self {
16 |         let state = Arc::new(ModelContextProtocolState {
17 |             contexts: raw_state.contexts,
18 |             root_path: raw_state.root_path,
19 |             project_config: raw_state.project_config,
20 |         });
21 |         let tools = get_all_mcp_tools(state);
22 |         let mut tool_router = ToolRouter::new();
23 |         tools.into_iter().for_each(|r| tool_router.add_route(r));
24 |         Self { tool_router }
25 |     }
26 | }
27 | 
28 | #[tool_handler]
29 | impl ServerHandler for McpServer {
30 |     async fn initialize(
31 |         &self,
32 |         _request: InitializeRequestParam,
33 |         _context: RequestContext<RoleServer>,
34 |     ) -> Result<rmcp::model::InitializeResult, McpError> {
35 |         Ok(ServerInfo {
36 |             protocol_version: ProtocolVersion::V_2024_11_05,
37 |             capabilities: ServerCapabilities::builder().enable_tools().build(),
38 |             server_info: Implementation::from_build_env(),
39 |             instructions: Some(
40 |                 "Intelligently search for patterns in Solidity codebases. To get started, call the tool guide."
41 |                     .to_string(),
42 |             ),
43 |         })
44 |     }
45 | }
46 | 
47 | #[derive(Clone)]
48 | pub struct SingletonMcpServer(Arc<McpServer>);
49 | 
50 | impl SingletonMcpServer {
51 |     pub fn new(inner: McpServer) -> Self {
52 |         Self(Arc::new(inner))
53 |     }
54 | }
55 | 
56 | impl ServerHandler for SingletonMcpServer {
57 |     fn initialize(
58 |         &self,
59 |         request: InitializeRequestParam,
60 |         context: RequestContext<RoleServer>,
61 |     ) -> impl std::future::Future<Output = Result<rmcp::model::InitializeResult, McpError>> + Send + '_
62 |     {
63 |         let inner = self.0.clone();
64 |         async move { inner.initialize(request, context).await }
65 |     }
66 | 
67 |     fn call_tool(
68 |         &self,
69 |         request: CallToolRequestParam,
70 |         context: RequestContext<RoleServer>,
71 |     ) -> impl std::future::Future<Output = Result<CallToolResult, McpError>> + Send + '_ {
72 |         let inner = self.0.clone();
73 |         async move { inner.call_tool(request, context).await }
74 |     }
75 | 
76 |     fn list_tools(
77 |         &self,
78 |         request: Option<PaginatedRequestParam>,
79 |         context: RequestContext<RoleServer>,
80 |     ) -> impl std::future::Future<Output = Result<ListToolsResult, McpError>> + Send + '_ {
81 |         let inner = self.0.clone();
82 |         async move { inner.list_tools(request, context).await }
83 |     }
84 | }
85 | 
```

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

```rust
 1 | use crate::context::{
 2 |     macros::{mcp_error, mcp_success},
 3 |     mcp::{
 4 |         MCPToolNamePool, ModelContextProtocolState, ModelContextProtocolTool,
 5 |         list_contracts::render::{ContractInfoBuilder, ContractsListBuilder},
 6 |     },
 7 | };
 8 | use indoc::indoc;
 9 | use rmcp::{
10 |     ErrorData as McpError, handler::server::wrapper::Parameters, model::CallToolResult, schemars,
11 | };
12 | use serde::Deserialize;
13 | use std::sync::Arc;
14 | 
15 | #[derive(Clone)]
16 | pub struct ListContractsTool {
17 |     state: Arc<ModelContextProtocolState>,
18 | }
19 | 
20 | #[derive(Deserialize, schemars::JsonSchema)]
21 | pub struct ListContractsPayload {
22 |     /// The index of the compilation unit to analyze. Must be a positive integer starting from 1.
23 |     /// Use the project overview tool first to see all available compilation units and their
24 |     /// indices.
25 |     pub compilation_unit_index: usize,
26 | }
27 | 
28 | impl ModelContextProtocolTool for ListContractsTool {
29 |     type Input = ListContractsPayload;
30 | 
31 |     fn new(state: Arc<ModelContextProtocolState>) -> Self {
32 |         Self { state }
33 |     }
34 | 
35 |     fn name(&self) -> String {
36 |         MCPToolNamePool::AderynListContracts.to_string()
37 |     }
38 | 
39 |     fn description(&self) -> String {
40 |         indoc! {
41 |             "Enumerates deployable contracts within a specific compilation unit. Returns contract names, \
42 |             file names (relative to the project root) and node IDs."
43 |         }
44 |         .to_string()
45 |     }
46 | 
47 |     fn execute(&self, input: Parameters<Self::Input>) -> Result<CallToolResult, McpError> {
48 |         let comp_unit_idx = input.0.compilation_unit_index;
49 |         if comp_unit_idx < 1 || comp_unit_idx > self.state.contexts.len() {
50 |             return mcp_error!(
51 |                 "invalid value passed for compilation unit - must be in the range [1, {}] inclusive",
52 |                 self.state.contexts.len()
53 |             );
54 |         }
55 |         let context = self.state.contexts.get(comp_unit_idx - 1).expect("bounds check failed");
56 |         let mut contracts_info = vec![];
57 |         for contract in context.deployable_contracts() {
58 |             let (filepath, _, _) = context.get_node_sort_key_from_capturable(&contract.into());
59 |             let contract_info = ContractInfoBuilder::default()
60 |                 .name(contract.name.clone())
61 |                 .filepath(filepath)
62 |                 .node_id(contract.id)
63 |                 .build()
64 |                 .expect("failed to build contract info");
65 |             contracts_info.push(contract_info);
66 |         }
67 | 
68 |         let contract_list = ContractsListBuilder::default()
69 |             .compilation_unit_index(comp_unit_idx)
70 |             .contracts_info(contracts_info)
71 |             .build()
72 |             .expect("failed to build contracts list");
73 | 
74 |         mcp_success!(contract_list)
75 |     }
76 | }
77 | 
```

--------------------------------------------------------------------------------
/tests/ast/base_constructor_call.json:
--------------------------------------------------------------------------------

```json
1 | {"absolutePath":"a","exportedSymbols":{"A":[7],"C":[17]},"id":18,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"A","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":7,"linearizedBaseContracts":[7],"name":"A","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":5,"nodeType":"Block","src":"31:2:1","statements":[]},"id":6,"implemented":true,"kind":"constructor","modifiers":[],"name":"","nameLocation":"-1:-1:-1","nodeType":"FunctionDefinition","parameters":{"id":3,"nodeType":"ParameterList","parameters":[{"constant":false,"id":2,"mutability":"mutable","name":"","nameLocation":"-1:-1:-1","nodeType":"VariableDeclaration","scope":6,"src":"25:4:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1,"name":"uint","nodeType":"ElementaryTypeName","src":"25:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"src":"24:6:1"},"returnParameters":{"id":4,"nodeType":"ParameterList","parameters":[],"src":"31:0:1"},"scope":7,"src":"13:20:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":18,"src":"0:35:1","usedErrors":[]},{"abstract":false,"baseContracts":[{"baseName":{"id":8,"name":"A","nameLocations":["50:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":7,"src":"50:1:1"},"id":9,"nodeType":"InheritanceSpecifier","src":"50:1:1"}],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":17,"linearizedBaseContracts":[17,7],"name":"C","nameLocation":"45:1:1","nodeType":"ContractDefinition","nodes":[{"body":{"id":15,"nodeType":"Block","src":"73:2:1","statements":[]},"id":16,"implemented":true,"kind":"constructor","modifiers":[{"arguments":[{"hexValue":"32","id":12,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"70:1:1","typeDescriptions":{"typeIdentifier":"t_rational_2_by_1","typeString":"int_const 2"},"value":"2"}],"id":13,"kind":"baseConstructorSpecifier","modifierName":{"id":11,"name":"A","nameLocations":["68:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":7,"src":"68:1:1"},"nodeType":"ModifierInvocation","src":"68:4:1"}],"name":"","nameLocation":"-1:-1:-1","nodeType":"FunctionDefinition","parameters":{"id":10,"nodeType":"ParameterList","parameters":[],"src":"65:2:1"},"returnParameters":{"id":14,"nodeType":"ParameterList","parameters":[],"src":"73:0:1"},"scope":17,"src":"54:21:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":18,"src":"36:41:1","usedErrors":[]}],"src":"0:78:1"}
2 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/empty_require_revert.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 EmptyRequireRevertDetector {
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 EmptyRequireRevertDetector {
19 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
20 |         // Collect all require statements without a string literal.
21 |         let requires_and_reverts = context
22 |             .identifiers()
23 |             .into_iter()
24 |             .filter(|&id| id.name == "revert" || id.name == "require");
25 | 
26 |         for id in requires_and_reverts {
27 |             if (id.name == "revert" && id.argument_types.as_ref().unwrap().is_empty())
28 |                 || (id.name == "require" && id.argument_types.as_ref().unwrap().len() == 1)
29 |             {
30 |                 capture!(self, context, id);
31 |             }
32 |         }
33 | 
34 |         Ok(!self.found_instances.is_empty())
35 |     }
36 | 
37 |     fn title(&self) -> String {
38 |         String::from("Empty `require()` / `revert()` Statement")
39 |     }
40 | 
41 |     fn description(&self) -> String {
42 |         String::from("Use descriptive reason strings or custom errors for revert paths.")
43 |     }
44 | 
45 |     fn severity(&self) -> IssueSeverity {
46 |         IssueSeverity::Low
47 |     }
48 | 
49 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
50 |         self.found_instances.clone()
51 |     }
52 | 
53 |     fn name(&self) -> String {
54 |         format!("{}", IssueDetectorNamePool::EmptyRequireRevert)
55 |     }
56 | }
57 | 
58 | #[cfg(test)]
59 | mod require_with_string_tests {
60 | 
61 |     use crate::detect::detector::IssueDetector;
62 | 
63 |     use super::EmptyRequireRevertDetector;
64 | 
65 |     #[test]
66 |     fn test_require_with_string_by_loading_contract_directly() {
67 |         let context = crate::detect::test_utils::load_solidity_source_unit(
68 |             "../tests/contract-playground/src/DeprecatedOZFunctions.sol",
69 |         );
70 | 
71 |         let mut detector = EmptyRequireRevertDetector::default();
72 |         let found = detector.detect(&context).unwrap();
73 |         assert!(found);
74 |         assert_eq!(detector.instances().len(), 2);
75 |     }
76 | 
77 |     #[test]
78 |     fn test_require_with_custom_error_by_loading_contract_directly() {
79 |         let context = crate::detect::test_utils::load_solidity_source_unit(
80 |             "../tests/contract-playground/src/UnusedError.sol",
81 |         );
82 | 
83 |         let mut detector = EmptyRequireRevertDetector::default();
84 |         let found = detector.detect(&context).unwrap();
85 |         assert!(!found);
86 |     }
87 | }
88 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/context/graph/traits.rs:
--------------------------------------------------------------------------------

```rust
 1 | use crate::ast::{ASTNode, FunctionDefinition, ModifierDefinition};
 2 | 
 3 | /// Trait to support reversing of callgraph. (Because, direct impl is not allowed on Foreign Types)
 4 | pub trait Transpose {
 5 |     fn reverse(&self) -> Self;
 6 | }
 7 | 
 8 | /// Use with [`super::CallGraph`]
 9 | pub trait CallGraphVisitor {
10 |     /// Shift all logic to tracker otherwise, you would track state at 2 different places
11 |     /// One at the tracker level, and other at the application level. Instead, we must
12 |     /// contain all of the tracking logic in the tracker. Therefore, visit entry point
13 |     /// is essential because the tracker can get to take a look at not just the
14 |     /// inward functions and modifiers, but also the entry points that have invoked it.
15 |     fn visit_entry_point(&mut self, node: &ASTNode) -> eyre::Result<()> {
16 |         self.visit_any(node)
17 |     }
18 | 
19 |     /// Meant to be invoked while traversing
20 |     /// [`crate::context::workspace_context::WorkspaceContext::inward_callgraph`]
21 |     fn visit_inward_function_definition(&mut self, node: &FunctionDefinition) -> eyre::Result<()> {
22 |         self.visit_any(&(node.into()))
23 |     }
24 | 
25 |     /// Meant to be invoked while traversing
26 |     /// [`crate::context::workspace_context::WorkspaceContext::outward_callgraph`]
27 |     fn visit_outward_function_definition(&mut self, node: &FunctionDefinition) -> eyre::Result<()> {
28 |         self.visit_any(&(node.into()))
29 |     }
30 | 
31 |     /// Meant to be invoked while traversing
32 |     /// [`crate::context::workspace_context::WorkspaceContext::inward_callgraph`]
33 |     fn visit_inward_modifier_definition(&mut self, node: &ModifierDefinition) -> eyre::Result<()> {
34 |         self.visit_any(&(node.into()))
35 |     }
36 | 
37 |     /// Meant to be invoked while traversing
38 |     /// [`crate::context::workspace_context::WorkspaceContext::outward_callgraph`]
39 |     fn visit_outward_modifier_definition(&mut self, node: &ModifierDefinition) -> eyre::Result<()> {
40 |         self.visit_any(&(node.into()))
41 |     }
42 | 
43 |     /// Read as "outward's inward-side-effect" function definition
44 |     /// These are function definitions that are inward from the outward nodes
45 |     /// but are themselves neither outward nor inward to the entry points
46 |     fn visit_outward_side_effect_function_definition(
47 |         &mut self,
48 |         node: &FunctionDefinition,
49 |     ) -> eyre::Result<()> {
50 |         self.visit_any(&(node.into()))
51 |     }
52 | 
53 |     /// Read as "outward's inward-side-effect" modifier definition
54 |     /// These are modifier definitions that are inward from the outward nodes
55 |     /// but are themselves neither outward nor inward to the entry points
56 |     fn visit_outward_side_effect_modifier_definition(
57 |         &mut self,
58 |         node: &ModifierDefinition,
59 |     ) -> eyre::Result<()> {
60 |         self.visit_any(&(node.into()))
61 |     }
62 | 
63 |     fn visit_any(&mut self, _node: &ASTNode) -> eyre::Result<()> {
64 |         Ok(())
65 |     }
66 | }
67 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/context/graph/preprocess/new.rs:
--------------------------------------------------------------------------------

```rust
 1 | use crate::{
 2 |     ast::ContractDefinition,
 3 |     context::{
 4 |         browser::{ExtractFunctionCalls, ExtractModifierInvocations},
 5 |         graph::*,
 6 |         workspace::WorkspaceContext,
 7 |     },
 8 | };
 9 | use std::collections::{HashSet, hash_map::*};
10 | 
11 | impl WorkspaceCallGraphs {
12 |     pub fn build(context: &WorkspaceContext) -> WorkspaceCallGraphs {
13 |         let mut workspace_cg: WorkspaceCallGraphs = Default::default();
14 |         for contract in context.deployable_contracts() {
15 |             if let Some(raw_callgraph) = _create_raw_callgraph(context, contract) {
16 |                 workspace_cg.inward_callgraphs.insert(contract.id, raw_callgraph.clone());
17 |                 workspace_cg.outward_callgraphs.insert(contract.id, raw_callgraph.reverse());
18 |             }
19 |         }
20 |         workspace_cg
21 |     }
22 | }
23 | 
24 | pub fn _create_raw_callgraph(
25 |     context: &WorkspaceContext,
26 |     contract: &ContractDefinition,
27 | ) -> Option<RawCallGraph> {
28 |     let mut raw_callgraph = Default::default();
29 |     let mut visited: HashSet<NodeID> = Default::default();
30 |     for entrypoint in context.entrypoint_functions(contract)? {
31 |         let mut current = vec![entrypoint.id];
32 |         while let Some(node_id) = current.pop() {
33 |             if visited.contains(&node_id) {
34 |                 continue;
35 |             }
36 |             visited.insert(node_id);
37 |             create_node_if_not_exists(node_id, &mut raw_callgraph);
38 |             let Some(node) = context.nodes.get(&node_id) else {
39 |                 continue;
40 |             };
41 |             for function_call in ExtractFunctionCalls::from(node).extracted {
42 |                 if let Some(f) = context.resolve_internal_call(contract, &function_call) {
43 |                     create_connection_if_not_exists(node_id, f.id, &mut raw_callgraph);
44 |                     current.push(f.id);
45 |                 }
46 |             }
47 |             for modifier_call in ExtractModifierInvocations::from(node).extracted {
48 |                 if let Some(m) = context.resolve_modifier_call(contract, &modifier_call) {
49 |                     create_connection_if_not_exists(node_id, m.id, &mut raw_callgraph);
50 |                     current.push(m.id);
51 |                 }
52 |             }
53 |         }
54 |     }
55 |     Some(raw_callgraph)
56 | }
57 | 
58 | fn create_node_if_not_exists(node_id: NodeID, raw_callgraph: &mut RawCallGraph) {
59 |     if let Entry::Vacant(v) = raw_callgraph.entry(node_id) {
60 |         v.insert(vec![]);
61 |     }
62 | }
63 | 
64 | fn create_connection_if_not_exists(
65 |     from_id: NodeID,
66 |     to_id: NodeID,
67 |     raw_callgraph: &mut RawCallGraph,
68 | ) {
69 |     match raw_callgraph.entry(from_id) {
70 |         Entry::Occupied(mut o) => {
71 |             // Performance Tip: Maybe later use binary search (it requires keeping ascending order
72 |             // while inserting tho)
73 |             if !o.get().contains(&to_id) {
74 |                 o.get_mut().push(to_id);
75 |             }
76 |         }
77 |         Entry::Vacant(v) => {
78 |             v.insert(vec![to_id]);
79 |         }
80 |     }
81 | }
82 | 
```

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

```rust
 1 | use std::{collections::BTreeMap, error::Error};
 2 | 
 3 | use crate::ast::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 DynamicArrayLengthAssignmentDetector {
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 DynamicArrayLengthAssignmentDetector {
20 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
21 |         for member_access in context
22 |             .member_accesses()
23 |             .into_iter()
24 |             .filter(|member_access| member_access.l_value_requested)
25 |         {
26 |             let assignment_to = member_access.expression.type_descriptions();
27 | 
28 |             let is_being_assigned_on_dynamic_array = assignment_to.is_some_and(|assignment_to| {
29 |                 assignment_to
30 |                     .type_string
31 |                     .as_ref()
32 |                     .is_some_and(|type_string| type_string.ends_with("[] storage ref"))
33 |             });
34 | 
35 |             let is_being_assigned_to_length_property = member_access.member_name == "length";
36 | 
37 |             if is_being_assigned_on_dynamic_array && is_being_assigned_to_length_property {
38 |                 capture!(self, context, member_access);
39 |             }
40 |         }
41 | 
42 |         Ok(!self.found_instances.is_empty())
43 |     }
44 | 
45 |     fn severity(&self) -> IssueSeverity {
46 |         IssueSeverity::High
47 |     }
48 | 
49 |     fn title(&self) -> String {
50 |         String::from("Direct assignment of array length")
51 |     }
52 | 
53 |     fn description(&self) -> String {
54 |         String::from(
55 |             "If the length of a dynamic array (storage variable) is directly assigned to, \
56 |         it may allow access to other storage slots by tweaking it's value. This practice has \
57 |         been deprecated in newer Solidity versions",
58 |         )
59 |     }
60 | 
61 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
62 |         self.found_instances.clone()
63 |     }
64 | 
65 |     fn name(&self) -> String {
66 |         IssueDetectorNamePool::DynamicArrayLengthAssignment.to_string()
67 |     }
68 | }
69 | 
70 | #[cfg(test)]
71 | mod dynamic_array_length_assignment_tests {
72 | 
73 |     use crate::detect::{
74 |         detector::IssueDetector, high::DynamicArrayLengthAssignmentDetector,
75 |         test_utils::load_solidity_source_unit,
76 |     };
77 | 
78 |     #[test]
79 | 
80 |     fn test_dynamic_array_length_assignment() {
81 |         let context = load_solidity_source_unit(
82 |             "../tests/contract-playground/src/DynamicArrayLengthAssignment.sol",
83 |         );
84 | 
85 |         let mut detector = DynamicArrayLengthAssignmentDetector::default();
86 |         let found = detector.detect(&context).unwrap();
87 | 
88 |         assert!(found);
89 |         assert_eq!(detector.instances().len(), 5);
90 |     }
91 | }
92 | 
```

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

```rust
 1 | use std::{collections::BTreeMap, error::Error};
 2 | 
 3 | use crate::ast::{Expression, NodeID, NodeType};
 4 | 
 5 | use crate::{
 6 |     capture,
 7 |     context::{browser::GetImmediateParent, workspace::WorkspaceContext},
 8 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 9 | };
10 | use eyre::Result;
11 | 
12 | // HOW TO USE THIS TEMPLATE:
13 | // 1. Copy this file and rename it to the snake_case version of the issue you are detecting.
14 | // 2. Rename the RedundantStatementDetector struct and impl to your new issue name.
15 | // 3. Add this file and detector struct to the mod.rs file in the same directory.
16 | // 4. Implement the detect function to find instances of the issue.
17 | 
18 | #[derive(Default)]
19 | pub struct RedundantStatementDetector {
20 |     // Keys are: [0] source file name, [1] line number, [2] character location of node.
21 |     // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
22 |     found_instances: BTreeMap<(String, usize, String), NodeID>,
23 | }
24 | 
25 | impl IssueDetector for RedundantStatementDetector {
26 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
27 |         for expression_statement in context.expression_statements() {
28 |             if let Some(parent) = expression_statement.parent(context) {
29 |                 if parent.node_type() != NodeType::Block {
30 |                     continue;
31 |                 }
32 | 
33 |                 match &expression_statement.expression {
34 |                     Expression::Identifier(identifier) => {
35 |                         capture!(self, context, identifier);
36 |                     }
37 |                     Expression::ElementaryTypeNameExpression(elementary_type_expression) => {
38 |                         capture!(self, context, elementary_type_expression);
39 |                     }
40 |                     _ => (),
41 |                 };
42 |             }
43 |         }
44 | 
45 |         Ok(!self.found_instances.is_empty())
46 |     }
47 | 
48 |     fn severity(&self) -> IssueSeverity {
49 |         IssueSeverity::Low
50 |     }
51 | 
52 |     fn title(&self) -> String {
53 |         String::from("Redundant Statement")
54 |     }
55 | 
56 |     fn description(&self) -> String {
57 |         String::from("Remove the redundant statement.")
58 |     }
59 | 
60 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
61 |         self.found_instances.clone()
62 |     }
63 | 
64 |     fn name(&self) -> String {
65 |         IssueDetectorNamePool::RedundantStatement.to_string()
66 |     }
67 | }
68 | 
69 | #[cfg(test)]
70 | mod redundant_statements_detector {
71 | 
72 |     use crate::detect::{
73 |         detector::IssueDetector, low::redundant_statement::RedundantStatementDetector,
74 |     };
75 | 
76 |     #[test]
77 | 
78 |     fn test_redundant_statements() {
79 |         let context = crate::detect::test_utils::load_solidity_source_unit(
80 |             "../tests/contract-playground/src/RedundantStatements.sol",
81 |         );
82 | 
83 |         let mut detector = RedundantStatementDetector::default();
84 |         let found = detector.detect(&context).unwrap();
85 |         assert!(found);
86 |         assert_eq!(detector.instances().len(), 6);
87 |     }
88 | }
89 | 
```

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

```rust
 1 | use std::{collections::BTreeMap, error::Error};
 2 | 
 3 | use crate::{
 4 |     ast::NodeID,
 5 |     capture,
 6 |     context::{
 7 |         browser::Peek,
 8 |         workspace::{ASTNode, WorkspaceContext},
 9 |     },
10 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
11 |     stats,
12 | };
13 | use eyre::Result;
14 | 
15 | #[derive(Default)]
16 | pub struct TodoDetector {
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 |     hints: BTreeMap<(String, usize, String), String>,
21 | }
22 | 
23 | impl IssueDetector for TodoDetector {
24 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
25 |         for contract in context.contract_definitions() {
26 |             let contract_as_ast: ASTNode = contract.into();
27 |             if let Some(contract_code) = contract_as_ast.peek(context) {
28 |                 if contract_code.is_empty() {
29 |                     continue;
30 |                 }
31 |                 let tokens = stats::token::tokenize(&contract_code);
32 |                 for token in tokens {
33 |                     match token.token_type {
34 |                         stats::token::TokenType::MultilineComment
35 |                         | stats::token::TokenType::SinglelineComment => {
36 |                             if token.content.to_lowercase().contains("todo") {
37 |                                 capture!(self, context, contract);
38 |                                 break;
39 |                             }
40 |                         }
41 |                         _ => (),
42 |                     }
43 |                 }
44 |             }
45 |         }
46 | 
47 |         Ok(!(self.found_instances.is_empty()))
48 |     }
49 | 
50 |     fn title(&self) -> String {
51 |         String::from("Contract has TODO Comments")
52 |     }
53 | 
54 |     fn description(&self) -> String {
55 |         String::from(
56 |             "Contract contains comments with TODOS. Consider implementing or removing them.",
57 |         )
58 |     }
59 | 
60 |     fn severity(&self) -> IssueSeverity {
61 |         IssueSeverity::Low
62 |     }
63 | 
64 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
65 |         self.found_instances.clone()
66 |     }
67 | 
68 |     fn hints(&self) -> BTreeMap<(String, usize, String), String> {
69 |         self.hints.clone()
70 |     }
71 | 
72 |     fn name(&self) -> String {
73 |         format!("{}", IssueDetectorNamePool::Todo)
74 |     }
75 | }
76 | 
77 | #[cfg(test)]
78 | mod contracts_with_todos_tests {
79 | 
80 |     use crate::detect::detector::IssueDetector;
81 | 
82 |     use super::TodoDetector;
83 | 
84 |     #[test]
85 | 
86 |     fn test_contracts_with_todos_by_loading_contract_directly() {
87 |         let context = crate::detect::test_utils::load_solidity_source_unit(
88 |             "../tests/contract-playground/src/ContractWithTodo.sol",
89 |         );
90 | 
91 |         let mut detector = TodoDetector::default();
92 |         let found = detector.detect(&context).unwrap();
93 | 
94 |         assert!(found);
95 |         assert_eq!(detector.instances().len(), 1);
96 |     }
97 | }
98 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/unchecked_send.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::{browser::GetImmediateParent, workspace::WorkspaceContext},
 8 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 9 | };
10 | use eyre::Result;
11 | 
12 | #[derive(Default)]
13 | pub struct UncheckedSendDetector {
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 UncheckedSendDetector {
20 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
21 |         for member_access in context.member_accesses() {
22 |             if member_access.member_name == "send"
23 |                 && member_access.expression.type_descriptions().is_some_and(|type_desc| {
24 |                     type_desc.type_string.as_ref().is_some_and(|type_string| {
25 |                         type_string == "address" || type_string == "address payable"
26 |                     })
27 |                 })
28 |                 && let Some(ASTNode::FunctionCall(func_call)) = member_access.parent(context)
29 |                 && let Some(ASTNode::ExpressionStatement(expr_stmnt)) = func_call.parent(context)
30 |                 && expr_stmnt
31 |                     .parent(context)
32 |                     .is_some_and(|node| node.node_type() == NodeType::Block)
33 |             {
34 |                 capture!(self, context, func_call);
35 |             }
36 |         }
37 | 
38 |         Ok(!self.found_instances.is_empty())
39 |     }
40 | 
41 |     fn severity(&self) -> IssueSeverity {
42 |         IssueSeverity::High
43 |     }
44 | 
45 |     fn title(&self) -> String {
46 |         String::from("Unchecked `bool success` value for ETH send")
47 |     }
48 | 
49 |     fn description(&self) -> String {
50 |         String::from(
51 |             "The call `address(payable?).send(address)` may fail because of reasons like out-of-gas, \
52 |         invalid recipient address or revert from the recipient, but not revert the transaction. Therefore, the boolean returned by this function call must be checked \
53 |         to be `true` in order to verify that the transaction was successful.",
54 |         )
55 |     }
56 | 
57 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
58 |         self.found_instances.clone()
59 |     }
60 | 
61 |     fn name(&self) -> String {
62 |         IssueDetectorNamePool::UncheckedSend.to_string()
63 |     }
64 | }
65 | 
66 | #[cfg(test)]
67 | mod unchecked_send_tests {
68 | 
69 |     use crate::detect::{detector::IssueDetector, high::unchecked_send::UncheckedSendDetector};
70 | 
71 |     #[test]
72 |     fn test_unchecked_send() {
73 |         let context = crate::detect::test_utils::load_solidity_source_unit(
74 |             "../tests/contract-playground/src/UncheckedSend.sol",
75 |         );
76 | 
77 |         let mut detector = UncheckedSendDetector::default();
78 |         let found = detector.detect(&context).unwrap();
79 | 
80 |         assert!(found);
81 |         assert_eq!(detector.instances().len(), 1);
82 |     }
83 | }
84 | 
```

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

```rust
 1 | use std::{
 2 |     collections::{BTreeMap, HashMap},
 3 |     error::Error,
 4 | };
 5 | 
 6 | use crate::ast::{ContractDefinition, NodeID};
 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 ReusedContractNameDetector {
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 ReusedContractNameDetector {
23 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
24 |         let mut contract_names: HashMap<&str, Vec<&ContractDefinition>> = HashMap::new();
25 | 
26 |         // Simplify the map filling process using the Entry API
27 |         for contract in context.contract_definitions() {
28 |             contract_names.entry(&contract.name).or_default().push(contract);
29 |         }
30 | 
31 |         // Process duplicate contracts
32 |         contract_names
33 |             .values() // Directly iterate over values
34 |             .filter(|contracts| contracts.len() > 1) // Filter for duplicates
35 |             .flatten() // Flatten the list of lists to a single list of contracts
36 |             .for_each(|contract| capture!(self, context, contract)); // Process each contract
37 | 
38 |         Ok(!self.found_instances.is_empty())
39 |     }
40 | 
41 |     fn severity(&self) -> IssueSeverity {
42 |         IssueSeverity::High
43 |     }
44 | 
45 |     fn title(&self) -> String {
46 |         String::from("Contract Name Reused in Different Files")
47 |     }
48 | 
49 |     fn description(&self) -> String {
50 |         String::from(
51 |             "When compiling contracts with certain development frameworks (for example: Truffle), having contracts with the same name across different files can lead to one being overwritten.",
52 |         )
53 |     }
54 | 
55 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
56 |         self.found_instances.clone()
57 |     }
58 | 
59 |     fn name(&self) -> String {
60 |         IssueDetectorNamePool::ReusedContractName.to_string()
61 |     }
62 | }
63 | 
64 | #[cfg(test)]
65 | mod reused_contract_name_detector_tests {
66 |     use semver::Version;
67 | 
68 |     use crate::detect::{
69 |         detector::IssueDetector, high::ReusedContractNameDetector,
70 |         test_utils::load_multiple_solidity_source_units_into_single_context,
71 |     };
72 | 
73 |     #[test]
74 | 
75 |     fn test_reused_contract_name_detector() {
76 |         let context = load_multiple_solidity_source_units_into_single_context(
77 |             &[
78 |                 "../tests/contract-playground/src/reused_contract_name/ContractA.sol",
79 |                 "../tests/contract-playground/src/reused_contract_name/ContractB.sol",
80 |             ],
81 |             Version::new(0, 8, 19),
82 |         );
83 | 
84 |         let mut detector = ReusedContractNameDetector::default();
85 |         let found = detector.detect(&context).unwrap();
86 |         assert!(found);
87 |         assert_eq!(detector.instances().len(), 2);
88 |     }
89 | }
90 | 
```

--------------------------------------------------------------------------------
/aderyn_core/tests/traversal.rs:
--------------------------------------------------------------------------------

```rust
  1 | mod common;
  2 | 
  3 | use aderyn_core::detect::{detector::IssueDetector, test_utils::load_solidity_source_unit};
  4 | use common::*;
  5 | 
  6 | #[test]
  7 | fn test_immediate_parent_demo() {
  8 |     let context = load_solidity_source_unit(
  9 |         "../tests/contract-playground/src/parent_chain/ParentChainContract.sol",
 10 |     );
 11 | 
 12 |     let mut detector = ImmediateParentDemonstrator::default();
 13 |     let found = detector.detect(&context).unwrap();
 14 |     assert!(found);
 15 | 
 16 |     println!("Total number of instances: {:?}", detector.instances().len());
 17 |     assert!(detector.instances().len() == 3);
 18 | }
 19 | 
 20 | #[test]
 21 | fn test_immediate_child_demo() {
 22 |     let context = load_solidity_source_unit(
 23 |         "../tests/contract-playground/src/parent_chain/ParentChainContract.sol",
 24 |     );
 25 | 
 26 |     let mut detector = ImmediateChildrenDemonstrator::default();
 27 |     let found = detector.detect(&context).unwrap();
 28 |     assert!(found);
 29 | 
 30 |     println!("Total number of instances: {:?}", detector.instances().len());
 31 |     assert!(detector.instances().len() == 1);
 32 | }
 33 | 
 34 | #[test]
 35 | fn test_closest_ancestor() {
 36 |     let context = load_solidity_source_unit(
 37 |         "../tests/contract-playground/src/parent_chain/ParentChainContract.sol",
 38 |     );
 39 | 
 40 |     let mut detector = ClosestAncestorDemonstrator::default();
 41 |     let found = detector.detect(&context).unwrap();
 42 |     assert!(found);
 43 | 
 44 |     println!("Total number of instances: {:?}", detector.instances().len());
 45 |     assert!(detector.instances().len() == 4);
 46 | }
 47 | 
 48 | #[test]
 49 | fn test_ancestral_line_demo() {
 50 |     let context = load_solidity_source_unit(
 51 |         "../tests/contract-playground/src/parent_chain/ParentChainContract.sol",
 52 |     );
 53 | 
 54 |     let mut detector = AncestralLineDemonstrator::default();
 55 |     let found = detector.detect(&context).unwrap();
 56 |     assert!(found);
 57 | 
 58 |     println!("Total number of instances: {:?}", detector.instances().len());
 59 |     assert!(detector.instances().len() == 4);
 60 | }
 61 | 
 62 | #[test]
 63 | fn test_new_ast_nodes() {
 64 |     let context = load_solidity_source_unit("../tests/adhoc-sol-files/DemoASTNodes.sol");
 65 | 
 66 |     let mut detector = NewASTNodesDemonstrator::default();
 67 |     let _ = detector.detect(&context).unwrap();
 68 | 
 69 |     let instances = detector.instances();
 70 |     //println!("{:?}", instances);
 71 | 
 72 |     assert!(instances.len() == 4);
 73 | }
 74 | 
 75 | #[test]
 76 | fn transient_can_compile() {
 77 |     load_solidity_source_unit("../tests/contract-playground/src/TransientKeyword.sol");
 78 | }
 79 | 
 80 | #[test]
 81 | fn test_peek_over() {
 82 |     let context =
 83 |         load_solidity_source_unit("../tests/contract-playground/src/StorageConditionals.sol");
 84 |     let mut detector = PeekOverDemonstrator::default();
 85 |     let _ = detector.detect(&context).unwrap();
 86 | 
 87 |     let instances = detector.instances();
 88 |     assert!(instances.len() == 2);
 89 | }
 90 | 
 91 | #[test]
 92 | fn test_siblings() {
 93 |     let context =
 94 |         load_solidity_source_unit("../tests/contract-playground/src/StorageConditionals.sol");
 95 | 
 96 |     let mut detector = SiblingDemonstrator::default();
 97 |     let _ = detector.detect(&context).unwrap();
 98 |     assert_eq!(detector.instances().len(), 1);
 99 | }
100 | 
```

--------------------------------------------------------------------------------
/tests/ast/used_errors.json:
--------------------------------------------------------------------------------

```json
1 | {"absolutePath":"a","exportedSymbols":{"C":[19],"X":[2],"f":[9]},"id":20,"nodeType":"SourceUnit","nodes":[{"errorSelector":"c1599bd9","id":2,"name":"X","nameLocation":"6:1:1","nodeType":"ErrorDefinition","parameters":{"id":1,"nodeType":"ParameterList","parameters":[],"src":"7:2:1"},"src":"0:10:1"},{"body":{"id":8,"nodeType":"Block","src":"29:15:1","statements":[{"errorCall":{"arguments":[],"expression":{"argumentTypes":[],"id":5,"name":"X","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":2,"src":"38:1:1","typeDescriptions":{"typeIdentifier":"t_function_error_pure$__$returns$__$","typeString":"function () pure"}},"id":6,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"38:3:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":7,"nodeType":"RevertStatement","src":"31:10:1"}]},"id":9,"implemented":true,"kind":"freeFunction","modifiers":[],"name":"f","nameLocation":"20:1:1","nodeType":"FunctionDefinition","parameters":{"id":3,"nodeType":"ParameterList","parameters":[],"src":"21:2:1"},"returnParameters":{"id":4,"nodeType":"ParameterList","parameters":[],"src":"29:0:1"},"scope":20,"src":"11:33:1","stateMutability":"pure","virtual":false,"visibility":"internal"},{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":19,"linearizedBaseContracts":[19],"name":"C","nameLocation":"54:1:1","nodeType":"ContractDefinition","nodes":[{"errorSelector":"2bc80f3a","id":11,"name":"T","nameLocation":"68:1:1","nodeType":"ErrorDefinition","parameters":{"id":10,"nodeType":"ParameterList","parameters":[],"src":"69:2:1"},"src":"62:10:1"},{"body":{"id":17,"nodeType":"Block","src":"97:8:1","statements":[{"expression":{"arguments":[],"expression":{"argumentTypes":[],"id":14,"name":"f","nodeType":"Identifier","overloadedDeclarations":[],"referencedDeclaration":9,"src":"99:1:1","typeDescriptions":{"typeIdentifier":"t_function_internal_pure$__$returns$__$","typeString":"function () pure"}},"id":15,"isConstant":false,"isLValue":false,"isPure":false,"kind":"functionCall","lValueRequested":false,"nameLocations":[],"names":[],"nodeType":"FunctionCall","src":"99:3:1","tryCall":false,"typeDescriptions":{"typeIdentifier":"t_tuple$__$","typeString":"tuple()"}},"id":16,"nodeType":"ExpressionStatement","src":"99:3:1"}]},"functionSelector":"b8c9d365","id":18,"implemented":true,"kind":"function","modifiers":[],"name":"h","nameLocation":"86:1:1","nodeType":"FunctionDefinition","parameters":{"id":12,"nodeType":"ParameterList","parameters":[],"src":"87:2:1"},"returnParameters":{"id":13,"nodeType":"ParameterList","parameters":[],"src":"97:0:1"},"scope":19,"src":"77:28:1","stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"scope":20,"src":"45:62:1","usedErrors":[2,11]}],"src":"0:108:1"}
2 | 
```

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

```rust
 1 | use std::{collections::BTreeMap, error::Error};
 2 | 
 3 | use crate::ast::{FunctionKind, NodeID};
 4 | 
 5 | use crate::{
 6 |     capture,
 7 |     context::{browser::ExtractFunctionDefinitions, workspace::WorkspaceContext},
 8 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
 9 | };
10 | use eyre::Result;
11 | 
12 | #[derive(Default)]
13 | pub struct MultipleConstructorsDetector {
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 MultipleConstructorsDetector {
20 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
21 |         let contracts_with_multiple_constructors = context
22 |             .contract_definitions()
23 |             .into_iter()
24 |             .filter(|&contract| {
25 |                 ExtractFunctionDefinitions::from(contract)
26 |                     .extracted
27 |                     .iter()
28 |                     .filter(|function| function.kind() == &FunctionKind::Constructor)
29 |                     .count()
30 |                     > 1
31 |             })
32 |             .collect::<Vec<_>>();
33 | 
34 |         for contract in contracts_with_multiple_constructors {
35 |             capture!(self, context, contract);
36 |         }
37 | 
38 |         Ok(!self.found_instances.is_empty())
39 |     }
40 | 
41 |     fn severity(&self) -> IssueSeverity {
42 |         IssueSeverity::High
43 |     }
44 | 
45 |     fn title(&self) -> String {
46 |         String::from("Contract Has Multiple Constructors")
47 |     }
48 | 
49 |     fn description(&self) -> String {
50 |         String::from(
51 |             "In some versions of Solidity, contracts compile with multiple constructors. The first constructor takes precedence. This can lead to unexpected behavior.",
52 |         )
53 |     }
54 | 
55 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
56 |         self.found_instances.clone()
57 |     }
58 | 
59 |     fn name(&self) -> String {
60 |         IssueDetectorNamePool::MultipleConstructors.to_string()
61 |     }
62 | }
63 | 
64 | #[cfg(test)]
65 | mod multiple_constructors_detector_tests {
66 | 
67 |     use crate::detect::{detector::IssueDetector, high::MultipleConstructorsDetector};
68 | 
69 |     #[test]
70 | 
71 |     fn test_multiple_constructors_detector() {
72 |         let context = crate::detect::test_utils::load_solidity_source_unit(
73 |             "../tests/contract-playground/src/MultipleConstructorSchemes.sol",
74 |         );
75 | 
76 |         let mut detector = MultipleConstructorsDetector::default();
77 |         let found = detector.detect(&context).unwrap();
78 |         assert!(found);
79 |         assert_eq!(detector.instances().len(), 1);
80 |     }
81 | 
82 |     #[test]
83 | 
84 |     fn test_multiple_constructors_detector_no_issue() {
85 |         let context = crate::detect::test_utils::load_solidity_source_unit(
86 |             "../tests/contract-playground/src/ArbitraryTransferFrom.sol",
87 |         );
88 | 
89 |         let mut detector = MultipleConstructorsDetector::default();
90 |         let found = detector.detect(&context).unwrap();
91 |         assert!(!found);
92 |         assert_eq!(detector.instances().len(), 0);
93 |     }
94 | }
95 | 
```

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

```rust
 1 | use std::{collections::BTreeMap, error::Error};
 2 | 
 3 | use crate::ast::{ASTNode, ContractKind, FunctionKind, NodeID, NodeType, Visibility};
 4 | 
 5 | use crate::{
 6 |     capture,
 7 |     context::{browser::GetClosestAncestorOfTypeX, workspace::WorkspaceContext},
 8 |     detect::{
 9 |         detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
10 |         helpers,
11 |     },
12 | };
13 | use eyre::Result;
14 | 
15 | #[derive(Default)]
16 | pub struct DeadCodeDetector {
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 DeadCodeDetector {
23 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
24 |         // Heuristic:
25 |         // Internal non overriding functions inside of non abstract contracts that have a body
26 |         // (implemented) and are not used If an internal function is marked override then,
27 |         // it may still be used even if it doesn't have a direct referencedDeclaration
28 |         // pointing to it.
29 | 
30 |         for func in context
31 |             .function_definitions()
32 |             .into_iter()
33 |             .filter(|&f| {
34 |                 f.overrides.is_none()
35 |                     && f.implemented
36 |                     && f.visibility == Visibility::Internal
37 |                     && f.kind() != &FunctionKind::Constructor
38 |             })
39 |             .filter(|&f| {
40 |                 if let Some(ASTNode::ContractDefinition(contract)) =
41 |                     f.closest_ancestor_of_type(context, NodeType::ContractDefinition)
42 |                     && contract.kind == ContractKind::Contract
43 |                     && !contract.is_abstract
44 |                 {
45 |                     return true;
46 |                 }
47 |                 false
48 |             })
49 |         {
50 |             if helpers::count_identifiers_that_reference_an_id(context, func.id) == 0 {
51 |                 capture!(self, context, func);
52 |             }
53 |         }
54 | 
55 |         Ok(!self.found_instances.is_empty())
56 |     }
57 | 
58 |     fn severity(&self) -> IssueSeverity {
59 |         IssueSeverity::Low
60 |     }
61 | 
62 |     fn title(&self) -> String {
63 |         String::from("Dead Code")
64 |     }
65 | 
66 |     fn description(&self) -> String {
67 |         String::from("Functions that are not used. Consider removing them.")
68 |     }
69 | 
70 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
71 |         self.found_instances.clone()
72 |     }
73 | 
74 |     fn name(&self) -> String {
75 |         format!("{}", IssueDetectorNamePool::DeadCode)
76 |     }
77 | }
78 | 
79 | #[cfg(test)]
80 | mod dead_code_tests {
81 | 
82 |     use crate::detect::{detector::IssueDetector, low::dead_code::DeadCodeDetector};
83 | 
84 |     #[test]
85 | 
86 |     fn test_dead_code() {
87 |         let context = crate::detect::test_utils::load_solidity_source_unit(
88 |             "../tests/contract-playground/src/DeadCode.sol",
89 |         );
90 | 
91 |         let mut detector = DeadCodeDetector::default();
92 |         let found = detector.detect(&context).unwrap();
93 |         assert!(found);
94 |         assert_eq!(detector.instances().len(), 1);
95 |     }
96 | }
97 | 
```

--------------------------------------------------------------------------------
/aderyn_core/tests/common/immediate_parent.rs:
--------------------------------------------------------------------------------

```rust
 1 | #![allow(clippy::collapsible_match)]
 2 | use std::{collections::BTreeMap, error::Error};
 3 | 
 4 | use aderyn_core::{
 5 |     ast::NodeID,
 6 |     capture,
 7 |     context::{
 8 |         browser::{AppearsAfterNodeLocation, AppearsBeforeNodeLocation, GetImmediateParent},
 9 |         workspace::{ASTNode, WorkspaceContext},
10 |     },
11 |     detect::detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
12 | };
13 | use eyre::Result;
14 | 
15 | #[derive(Default)]
16 | pub struct ImmediateParentDemonstrator {
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 | /*
23 | 
24 | In ParentChainContract.sol, there is only 1 assignment done. The goal is to capture it first, second and third parent
25 | */
26 | 
27 | impl IssueDetector for ImmediateParentDemonstrator {
28 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
29 |         for assignment in context.assignments() {
30 |             println!("0 {}", assignment);
31 |             capture!(self, context, assignment);
32 |             if let Some(first_parent) = assignment.parent(context)
33 |                 && let ASTNode::ExpressionStatement(expr_stmnt) = first_parent
34 |             {
35 |                 println!("1 {}", expr_stmnt);
36 |                 if let Some(second_parent) = first_parent.parent(context)
37 |                     && let ASTNode::Block(for_statement) = second_parent
38 |                 {
39 |                     println!("2 {}", for_statement);
40 |                     capture!(self, context, second_parent);
41 |                     if let Some(third_parent) = for_statement.parent(context) {
42 |                         if let ASTNode::ForStatement(block) = third_parent {
43 |                             println!("3 {}", block);
44 |                             capture!(self, context, third_parent);
45 |                         }
46 | 
47 |                         assert!(first_parent.appears_after(context, second_parent).unwrap());
48 |                         assert!(first_parent.appears_after(context, for_statement).unwrap());
49 |                         assert!(expr_stmnt.appears_after(context, for_statement).unwrap());
50 |                         assert!(second_parent.appears_after(context, third_parent).unwrap());
51 |                         assert!(second_parent.appears_before(context, first_parent).unwrap());
52 |                         assert!(third_parent.appears_before(context, second_parent).unwrap());
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("ImmediateParentDemonstrator")
67 |     }
68 | 
69 |     fn description(&self) -> String {
70 |         String::from("ImmediateParentDemonstrator")
71 |     }
72 | 
73 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
74 |         self.found_instances.clone()
75 |     }
76 | 
77 |     fn name(&self) -> String {
78 |         format!("{}", IssueDetectorNamePool::CentralizationRisk)
79 |     }
80 | }
81 | 
```

--------------------------------------------------------------------------------
/tests/ast/slot_offset.json:
--------------------------------------------------------------------------------

```json
1 | {"absolutePath":"a","exportedSymbols":{"C":[12]},"id":13,"nodeType":"SourceUnit","nodes":[{"abstract":false,"baseContracts":[],"canonicalName":"C","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"id":12,"linearizedBaseContracts":[12],"name":"C","nameLocation":"9:1:1","nodeType":"ContractDefinition","nodes":[{"canonicalName":"C.S","id":3,"members":[{"constant":false,"id":2,"mutability":"mutable","name":"x","nameLocation":"33:1:1","nodeType":"VariableDeclaration","scope":3,"src":"28:6:1","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":1,"name":"uint","nodeType":"ElementaryTypeName","src":"28:4:1","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"name":"S","nameLocation":"24:1:1","nodeType":"StructDefinition","scope":12,"src":"17:20:1","visibility":"public"},{"constant":false,"id":6,"mutability":"mutable","name":"s","nameLocation":"44:1:1","nodeType":"VariableDeclaration","scope":12,"src":"42:3:1","stateVariable":true,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_struct$_S_$3_storage","typeString":"struct C.S"},"typeName":{"id":5,"nodeType":"UserDefinedTypeName","pathNode":{"id":4,"name":"S","nameLocations":["42:1:1"],"nodeType":"IdentifierPath","referencedDeclaration":3,"src":"42:1:1"},"referencedDeclaration":3,"src":"42:1:1","typeDescriptions":{"typeIdentifier":"t_struct$_S_$3_storage_ptr","typeString":"struct C.S"}},"visibility":"internal"},{"body":{"id":10,"nodeType":"Block","src":"76:70:1","statements":[{"AST":{"nodeType":"YulBlock","src":"95:45:1","statements":[{"nodeType":"YulVariableDeclaration","src":"97:17:1","value":{"name":"s.offset","nodeType":"YulIdentifier","src":"106:8:1"},"variables":[{"name":"x","nodeType":"YulTypedName","src":"101:1:1","type":""}]},{"nodeType":"YulVariableDeclaration","src":"115:23:1","value":{"arguments":[{"name":"s.slot","nodeType":"YulIdentifier","src":"128:6:1"},{"kind":"number","nodeType":"YulLiteral","src":"136:1:1","type":"","value":"2"}],"functionName":{"name":"mul","nodeType":"YulIdentifier","src":"124:3:1"},"nodeType":"YulFunctionCall","src":"124:14:1"},"variables":[{"name":"y","nodeType":"YulTypedName","src":"119:1:1","type":""}]}]},"evmVersion":"london","externalReferences":[{"declaration":6,"isOffset":true,"isSlot":false,"src":"106:8:1","suffix":"offset","valueSize":1},{"declaration":6,"isOffset":false,"isSlot":true,"src":"128:6:1","suffix":"slot","valueSize":1}],"id":9,"nodeType":"InlineAssembly","src":"86:54:1"}]},"functionSelector":"ffae15ba","id":11,"implemented":true,"kind":"function","modifiers":[],"name":"e","nameLocation":"60:1:1","nodeType":"FunctionDefinition","parameters":{"id":7,"nodeType":"ParameterList","parameters":[],"src":"61:2:1"},"returnParameters":{"id":8,"nodeType":"ParameterList","parameters":[],"src":"76:0:1"},"scope":12,"src":"51:95:1","stateMutability":"pure","virtual":false,"visibility":"public"}],"scope":13,"src":"0:148:1","usedErrors":[]}],"src":"0:149:1"}
2 | 
```

--------------------------------------------------------------------------------
/tests/ast/do_while.json:
--------------------------------------------------------------------------------

```json
1 | {"absolutePath":"script/SomeScript.sol","id":39709,"exportedSymbols":{"Script":[113],"ScriptBase":[74],"SomeScript":[39708],"StdChains":[877],"StdCheatsSafe":[2937],"StdStorage":[4496],"StdStyle":[7346],"StdUtils":[8073],"VmSafe":[9693],"console":[18328],"console2":[26453],"safeconsole":[39691],"stdJson":[4322],"stdMath":[4464],"stdStorageSafe":[5544]},"nodeType":"SourceUnit","src":"0:188:14","nodes":[{"id":39693,"nodeType":"PragmaDirective","src":"0:23:14","nodes":[],"literals":["solidity","0.8",".23"]},{"id":39694,"nodeType":"ImportDirective","src":"25:30:14","nodes":[],"absolutePath":"lib/forge-std/src/Script.sol","file":"forge-std/Script.sol","nameLocation":"-1:-1:-1","scope":39709,"sourceUnit":114,"symbolAliases":[],"unitAlias":""},{"id":39708,"nodeType":"ContractDefinition","src":"57:131:14","nodes":[{"id":39707,"nodeType":"FunctionDefinition","src":"93:93:14","nodes":[],"body":{"id":39706,"nodeType":"Block","src":"115:71:14","nodes":[],"statements":[{"body":{"id":39703,"nodeType":"Block","src":"128:38:14","statements":[{"assignments":[39700],"declarations":[{"constant":false,"id":39700,"mutability":"mutable","name":"a","nameLocation":"150:1:14","nodeType":"VariableDeclaration","scope":39703,"src":"142:9:14","stateVariable":false,"storageLocation":"default","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"},"typeName":{"id":39699,"name":"uint256","nodeType":"ElementaryTypeName","src":"142:7:14","typeDescriptions":{"typeIdentifier":"t_uint256","typeString":"uint256"}},"visibility":"internal"}],"id":39702,"initialValue":{"hexValue":"31","id":39701,"isConstant":false,"isLValue":false,"isPure":true,"kind":"number","lValueRequested":false,"nodeType":"Literal","src":"154:1:14","typeDescriptions":{"typeIdentifier":"t_rational_1_by_1","typeString":"int_const 1"},"value":"1"},"nodeType":"VariableDeclarationStatement","src":"142:13:14"}]},"condition":{"hexValue":"66616c7365","id":39704,"isConstant":false,"isLValue":false,"isPure":true,"kind":"bool","lValueRequested":false,"nodeType":"Literal","src":"173:5:14","typeDescriptions":{"typeIdentifier":"t_bool","typeString":"bool"},"value":"false"},"id":39705,"nodeType":"DoWhileStatement","src":"125:55:14"}]},"functionSelector":"c0406226","implemented":true,"kind":"function","modifiers":[],"name":"run","nameLocation":"102:3:14","parameters":{"id":39697,"nodeType":"ParameterList","parameters":[],"src":"105:2:14"},"returnParameters":{"id":39698,"nodeType":"ParameterList","parameters":[],"src":"115:0:14"},"scope":39708,"stateMutability":"nonpayable","virtual":false,"visibility":"public"}],"abstract":false,"baseContracts":[{"baseName":{"id":39695,"name":"Script","nameLocations":["80:6:14"],"nodeType":"IdentifierPath","referencedDeclaration":113,"src":"80:6:14"},"id":39696,"nodeType":"InheritanceSpecifier","src":"80:6:14"}],"canonicalName":"SomeScript","contractDependencies":[],"contractKind":"contract","fullyImplemented":true,"linearizedBaseContracts":[39708,113,8073,2937,877,74,62],"name":"SomeScript","nameLocation":"66:10:14","scope":39709,"usedErrors":[],"usedEvents":[]}]}
```

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

```rust
 1 | use std::{collections::BTreeMap, error::Error};
 2 | 
 3 | use crate::ast::{ASTNode, FunctionKind, ModifierInvocationKind, 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 VoidConstructorDetector {
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 VoidConstructorDetector {
20 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
21 |         // PLAN
22 |         // Gather all the invocations of base constructors
23 |         // For each, inspect the contract and see if there is a constructor defined. If there isn't,
24 |         // capture the invocation
25 | 
26 |         for modifier_invocation in context.modifier_invocations() {
27 |             if modifier_invocation.kind != Some(ModifierInvocationKind::BaseConstructorSpecifier) {
28 |                 continue;
29 |             }
30 |             if let Some(reference_declaration) = match &modifier_invocation.modifier_name {
31 |                 crate::ast::IdentifierOrIdentifierPath::Identifier(identifier) => {
32 |                     identifier.referenced_declaration
33 |                 }
34 |                 crate::ast::IdentifierOrIdentifierPath::IdentifierPath(identifier_path) => {
35 |                     Some(identifier_path.referenced_declaration)
36 |                 }
37 |             } && let Some(ASTNode::ContractDefinition(contract)) =
38 |                 context.nodes.get(&reference_declaration)
39 |                 && contract
40 |                     .function_definitions()
41 |                     .into_iter()
42 |                     .filter(|f| *f.kind() == FunctionKind::Constructor)
43 |                     .count()
44 |                     == 0
45 |             {
46 |                 capture!(self, context, modifier_invocation);
47 |             }
48 |         }
49 | 
50 |         Ok(!self.found_instances.is_empty())
51 |     }
52 | 
53 |     fn severity(&self) -> IssueSeverity {
54 |         IssueSeverity::Low
55 |     }
56 | 
57 |     fn title(&self) -> String {
58 |         String::from("Void constructor")
59 |     }
60 | 
61 |     fn description(&self) -> String {
62 |         String::from("Call to a constructor that is not implemented.")
63 |     }
64 | 
65 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
66 |         self.found_instances.clone()
67 |     }
68 | 
69 |     fn name(&self) -> String {
70 |         format!("{}", IssueDetectorNamePool::VoidConstructor)
71 |     }
72 | }
73 | 
74 | #[cfg(test)]
75 | mod template_void_constructors {
76 | 
77 |     use crate::detect::{detector::IssueDetector, low::void_constructor::VoidConstructorDetector};
78 | 
79 |     #[test]
80 | 
81 |     fn test_template_detector() {
82 |         let context = crate::detect::test_utils::load_solidity_source_unit(
83 |             "../tests/contract-playground/src/VoidConstructor.sol",
84 |         );
85 | 
86 |         let mut detector = VoidConstructorDetector::default();
87 |         let found = detector.detect(&context).unwrap();
88 | 
89 |         assert!(found);
90 |         assert_eq!(detector.instances().len(), 1);
91 |     }
92 | }
93 | 
```

--------------------------------------------------------------------------------
/tools/xtask/src/reportgen.rs:
--------------------------------------------------------------------------------

```rust
  1 | use xshell::{Shell, cmd};
  2 | 
  3 | use crate::flags::Reportgen;
  4 | 
  5 | fn run_command(args: &str, release: bool) -> anyhow::Result<()> {
  6 |     let sh = Shell::new()?;
  7 |     sh.change_dir(env!("CARGO_MANIFEST_DIR"));
  8 |     sh.change_dir("../../");
  9 | 
 10 |     let mut cmd = cmd!(sh, "cargo run");
 11 |     if release {
 12 |         cmd = cmd.arg("--release");
 13 |     }
 14 |     cmd = cmd.arg("--").arg("--skip-update-check");
 15 |     cmd.args(args.split(" ")).run()?;
 16 |     Ok(())
 17 | }
 18 | 
 19 | fn run_command_with_env(args: &str, key: &str, val: &str, release: bool) -> anyhow::Result<()> {
 20 |     let sh = Shell::new()?;
 21 |     sh.change_dir(env!("CARGO_MANIFEST_DIR"));
 22 |     sh.change_dir("../../");
 23 | 
 24 |     let mut cmd = cmd!(sh, "cargo run");
 25 |     cmd = cmd.env(key, val);
 26 |     if release {
 27 |         cmd = cmd.arg("--release");
 28 |     }
 29 |     cmd = cmd.arg("--").arg("--skip-update-check");
 30 |     cmd.args(args.split(" ")).run()?;
 31 |     Ok(())
 32 | }
 33 | 
 34 | pub fn reportgen(choice: Reportgen) -> anyhow::Result<()> {
 35 |     if choice.all && choice.parallel {
 36 |         let sh = Shell::new()?;
 37 |         sh.change_dir(env!("CARGO_MANIFEST_DIR"));
 38 |         sh.change_dir("../../");
 39 | 
 40 |         let cmd = cmd!(sh, "chmod +x ./cli/reportgen.sh");
 41 |         cmd.run()?;
 42 |         let cmd = cmd!(sh, "./cli/reportgen.sh");
 43 |         cmd.run()?;
 44 | 
 45 |         return Ok(())
 46 |     }
 47 |     if choice.cpg || choice.all {
 48 |         run_command(
 49 |             "-i src/ -x lib/ ./tests/contract-playground -o ./reports/report.md",
 50 |             choice.release,
 51 |         )?;
 52 |     }
 53 |     if choice.adhoc || choice.all {
 54 |         run_command(
 55 |             "./tests/adhoc-sol-files -o ./reports/adhoc-sol-files-report.md",
 56 |             choice.release,
 57 |         )?;
 58 |     }
 59 |     if choice.sablier || choice.all {
 60 |         run_command(
 61 |             "./tests/2024-05-Sablier -o ./reports/sablier-aderyn-toml-nested-root.md",
 62 |             choice.release,
 63 |         )?;
 64 |     }
 65 |     if choice.fnft || choice.all {
 66 |         run_command(
 67 |             "./tests/foundry-nft-f23 -i src/ -x lib/ -o ./reports/nft-report.md",
 68 |             choice.release,
 69 |         )?;
 70 |     }
 71 |     if choice.fnft_icm || choice.all {
 72 |         run_command("./tests/foundry-nft-f23-icm -o ./reports/nft-report-icm.md", choice.release)?;
 73 |     }
 74 | 
 75 |     if choice.ccip || choice.all {
 76 |         run_command(
 77 |             "tests/ccip-contracts/contracts --src src/v0.8/functions/ -x tests/,test/,mocks/ -o ./reports/ccip-functions-report.md",
 78 |             choice.release,
 79 |         )?;
 80 |     }
 81 |     if choice.cpgu || choice.all {
 82 |         run_command_with_env(
 83 |             "tests/contract-playground/ -o ./reports/uniswap_profile.md",
 84 |             "FOUNDRY_PROFILE",
 85 |             "uniswap",
 86 |             choice.release,
 87 |         )?;
 88 |     }
 89 |     if choice.prb_math || choice.all {
 90 |         run_command("tests/prb-math -o reports/prb-math-report.md", choice.release)?;
 91 |     }
 92 |     if choice.tg || choice.all {
 93 |         run_command(
 94 |             "tests/2024-07-templegold/protocol -o reports/templegold-report.md",
 95 |             choice.release,
 96 |         )?;
 97 |     }
 98 |     if choice.hhpg || choice.all {
 99 |         run_command(
100 |             "tests/hardhat-js-playground -o reports/hardhat-playground-report.md",
101 |             choice.release,
102 |         )?;
103 |     }
104 |     Ok(())
105 | }
106 | 
```

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

```rust
  1 | pub mod detector;
  2 | pub mod entrypoint;
  3 | pub mod helpers;
  4 | pub mod high;
  5 | pub mod low;
  6 | 
  7 | pub mod test_utils;
  8 | 
  9 | #[macro_export]
 10 | macro_rules! capture {
 11 |     ($self:ident, $context:ident, $item:expr_2021) => {
 12 |         if let Some(id) = $context.get_node_id_of_capturable(&$item.clone().into()) {
 13 |             $self
 14 |                 .found_instances
 15 |                 .insert($context.get_node_sort_key_from_capturable(&$item.clone().into()), id);
 16 |         } else {
 17 |             $self
 18 |                 .found_instances
 19 |                 .insert($context.get_node_sort_key_from_capturable(&$item.clone().into()), 0);
 20 |         }
 21 |     };
 22 |     ($self:ident, $context:ident, $item:expr_2021, $hint:tt) => {
 23 |         $self
 24 |             .hints
 25 |             .insert($context.get_node_sort_key_from_capturable(&$item.clone().into()), $hint);
 26 |         capture!($self, $context, $item);
 27 |     };
 28 | }
 29 | 
 30 | #[macro_export]
 31 | macro_rules! issue_detector {
 32 |     (
 33 |         $detector_struct:ident;
 34 | 
 35 |         severity: $detector_severity:ident,
 36 |         title: $detector_title:tt,
 37 |         desc: $detector_desc:tt,
 38 |         name: $detector_name:ident,
 39 | 
 40 |         |$context: ident| $e:expr_2021
 41 |     ) => {
 42 | 
 43 |         #[derive(Default)]
 44 |         pub struct $detector_struct {
 45 |             found_instances: std::collections::BTreeMap<(String, usize, String), $crate::ast::NodeID>,
 46 |         }
 47 | 
 48 |         impl $crate::detect::detector::IssueDetector for $detector_struct {
 49 | 
 50 |             fn detect(&mut self, context: &$crate::context::workspace::WorkspaceContext) -> Result<bool, Box<dyn std::error::Error>> {
 51 | 
 52 |                 let $context = context;
 53 | 
 54 |                 macro_rules! grab {
 55 |                     ($item:expr_2021) => {
 56 |                         if let Some(id) = context.get_node_id_of_capturable(&$item.clone().into()) {
 57 |                             self.found_instances.insert(
 58 |                                 $context.get_node_sort_key_from_capturable(&$item.clone().into()),
 59 |                                 id,
 60 |                             );
 61 |                         } else {
 62 |                             self.found_instances.insert(
 63 |                                 $context.get_node_sort_key_from_capturable(&$item.clone().into()),
 64 |                                 0,
 65 |                             );
 66 |                         }
 67 |                     };
 68 |                 }
 69 | 
 70 |                 $e
 71 |                 Ok(!self.found_instances.is_empty())
 72 |             }
 73 | 
 74 |             fn severity(&self) -> $crate::detect::detector::IssueSeverity {
 75 |                 $crate::detect::detector::IssueSeverity::$detector_severity
 76 |             }
 77 | 
 78 |             fn title(&self) -> String {
 79 |                 String::from($detector_title)
 80 |             }
 81 | 
 82 |             fn description(&self) -> String {
 83 |                 String::from($detector_desc)
 84 |             }
 85 | 
 86 |             fn instances(&self) -> std::collections::BTreeMap<(String, usize, String), $crate::ast::NodeID> {
 87 |                 self.found_instances.clone()
 88 |             }
 89 | 
 90 |             fn name(&self) -> String {
 91 |                 $crate::detect::detector::IssueDetectorNamePool::$detector_name.to_string()
 92 |             }
 93 |         }
 94 | 
 95 |     };
 96 | }
 97 | 
 98 | pub use capture;
 99 | 
100 | pub use issue_detector;
101 | 
```

--------------------------------------------------------------------------------
/aderyn_core/src/detect/low/centralization_risk.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 CentralizationRiskDetector {
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 CentralizationRiskDetector {
19 |     fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
20 |         for contract_definition in context.contract_definitions().iter() {
21 |             for bc in contract_definition.base_contracts.iter() {
22 |                 if let Some(base_name) = bc.base_name.name()
23 |                     && matches!(
24 |                         base_name.as_str(),
25 |                         "Owned"
26 |                             | "Ownable"
27 |                             | "Ownable2Step"
28 |                             | "AccessControl"
29 |                             | "AccessControlCrossChain"
30 |                             | "AccessControlEnumerable"
31 |                             | "Auth"
32 |                             | "RolesAuthority"
33 |                             | "MultiRolesAuthority"
34 |                     )
35 |                 {
36 |                     capture!(self, context, bc);
37 |                 }
38 |             }
39 |         }
40 | 
41 |         for modifier_invocation in context.modifier_invocations().iter().filter(|&&mi| {
42 |             mi.modifier_name.name() == "onlyOwner"
43 |                 || mi.modifier_name.name() == "requiresAuth"
44 |                 || mi.modifier_name.name().contains("onlyRole")
45 |         }) {
46 |             capture!(self, context, modifier_invocation);
47 |         }
48 | 
49 |         Ok(!self.found_instances.is_empty())
50 |     }
51 | 
52 |     fn severity(&self) -> IssueSeverity {
53 |         IssueSeverity::Low
54 |     }
55 | 
56 |     fn title(&self) -> String {
57 |         String::from("Centralization Risk")
58 |     }
59 | 
60 |     fn description(&self) -> String {
61 |         String::from(
62 |             "Contracts have owners with privileged rights to perform admin tasks and need to be trusted to not perform malicious updates or drain funds.",
63 |         )
64 |     }
65 | 
66 |     fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
67 |         self.found_instances.clone()
68 |     }
69 | 
70 |     fn name(&self) -> String {
71 |         format!("{}", IssueDetectorNamePool::CentralizationRisk)
72 |     }
73 | }
74 | 
75 | #[cfg(test)]
76 | mod centralization_risk_detector_tests {
77 | 
78 |     use crate::detect::detector::IssueDetector;
79 | 
80 |     use super::CentralizationRiskDetector;
81 | 
82 |     #[test]
83 | 
84 |     fn test_centralization_risk_detector_by_loading_contract_directly() {
85 |         let context = crate::detect::test_utils::load_solidity_source_unit(
86 |             "../tests/contract-playground/src/AdminContract.sol",
87 |         );
88 | 
89 |         let mut detector = CentralizationRiskDetector::default();
90 |         let found = detector.detect(&context).unwrap();
91 |         assert!(found);
92 |         // assert that the number of instances found is 3
93 |         assert_eq!(detector.instances().len(), 3);
94 |     }
95 | }
96 | 
```
Page 6/103FirstPrevNextLast