#
tokens: 25946/50000 1/1140 files (page 89/94)
lines: off (toggle) GitHub
raw markdown copy
This is page 89 of 94. Use http://codebase.md/cyfrin/aderyn?lines=false&page={x} to view the full context.

# Directory Structure

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

# Files

--------------------------------------------------------------------------------
/aderyn_core/src/context/browser/storage_vars.rs:
--------------------------------------------------------------------------------

```rust
use crate::{
    ast::*,
    context::workspace::WorkspaceContext,
    visitor::ast_visitor::{ASTConstVisitor, Node},
};
use eyre::*;
use std::{
    collections::{BTreeMap, BTreeSet},
    fmt::Debug,
    iter::zip,
    ops::Add,
};

/// Given an AST Block, it tries to detect any state variable inside it that may have been
/// manipulated. Now it's important to know that manipulations can occur either directly by
/// assigning to a state variable or, it may occur by assigning to a storage pointer that points to
/// some state variable. This light weight state variable manipulation finder captures both of the
/// above kinds of assignments. However, it's not smart enough to use a data dependency graph to
/// determine the exact state variables these storage pointers would be pointing to, in the context
/// of the block-flow.
///
/// NOTE - Assignment is not the only avenue for manipulating state variables, but also operations
/// like `push()` and `pop()` on arrays, `M[i] = x` on mappings, `delete X` imply the same.
///
/// Here, the term manipulation covers all kinds of changes discussed above.
///
/// IMPORTANT: DO NOT MAKE THESE MEMBERS PUBLIC. Use the public methods implemented on this
/// structure only.
pub struct ApproximateStorageChangeFinder<'a> {
    directly_manipulated_state_variables: BTreeSet<NodeID>,
    manipulated_storage_pointers: BTreeSet<NodeID>,
    /// Key => State Variable ID, Value => Storage Pointer ID (Heuristics based, this map is NOT
    /// exhaustive) It leaves out a lot of links especially in cases where storage pointers are
    /// passed to and fro internal functions. But on average, for most cases the way code is
    /// generally written, this should contain a decent chunk of links to lookup.
    state_variables_to_storage_pointers: BTreeMap<NodeID, BTreeSet<NodeID>>,
    context: &'a WorkspaceContext,
}

/// This trait implementation will be useful when we run it through our callgraph and try to
/// aggregate state variable changes.
impl<'a> Add<ApproximateStorageChangeFinder<'_>> for ApproximateStorageChangeFinder<'a> {
    type Output = ApproximateStorageChangeFinder<'a>;

    fn add(mut self, rhs: ApproximateStorageChangeFinder) -> Self::Output {
        self.directly_manipulated_state_variables
            .extend(rhs.directly_manipulated_state_variables.iter());
        self.manipulated_storage_pointers.extend(rhs.manipulated_storage_pointers.iter());
        // For state_variables_to_storage_pointers, we have to "add" the storage point entry vectors
        for (state_var_id, storage_pointer_ids) in &rhs.state_variables_to_storage_pointers {
            match self.state_variables_to_storage_pointers.entry(*state_var_id) {
                std::collections::btree_map::Entry::Vacant(v) => {
                    v.insert(BTreeSet::from_iter(storage_pointer_ids.iter().copied()));
                }
                std::collections::btree_map::Entry::Occupied(mut o) => {
                    (*o.get_mut()).extend(storage_pointer_ids);
                }
            };
        }
        self
    }
}

impl Debug for ApproximateStorageChangeFinder<'_> {
    // Do not print context. Hence, debug is custom derived for this struct
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        writeln!(f, "Manipulated directly: {:?}", self.directly_manipulated_state_variables)?;

        if !self.directly_manipulated_state_variables.is_empty() {
            writeln!(f, "↓↓")?;
            for id in &self.directly_manipulated_state_variables {
                if let Some(node) = self.context.nodes.get(id) {
                    let loc_info = self.context.get_node_sort_key(node);
                    writeln!(f, "Line {:?}", (loc_info.1, loc_info.2))?;
                } else {
                    writeln!(f, "<unknown_node_id_{}>\n", id)?;
                }
            }
            writeln!(f)?;
        }

        writeln!(
            f,
            "Manipulated through storage pointers: {:?}",
            self.manipulated_storage_pointers
        )?;

        if !self.manipulated_storage_pointers.is_empty() {
            writeln!(f, "↓↓")?;
            for id in &self.manipulated_storage_pointers {
                if let Some(node) = self.context.nodes.get(id) {
                    let loc_info = self.context.get_node_sort_key(node);
                    writeln!(f, "Line {:?}", (loc_info.1, loc_info.2))?;
                } else {
                    writeln!(f, "<unknown_node_id_{}>", id)?;
                }
            }
            writeln!(f)?;
        }

        writeln!(f, "Links heuristics: {:?}", self.state_variables_to_storage_pointers)?;

        if !self.state_variables_to_storage_pointers.is_empty() {
            writeln!(f, "↓↓")?;
            for (state_variable_id, storage_pointer_references) in
                &self.state_variables_to_storage_pointers
            {
                if let Some(node) = self.context.nodes.get(state_variable_id) {
                    let loc_info = self.context.get_node_sort_key(node);
                    writeln!(f, "Links to {:?}", (loc_info.1, loc_info.2))?;
                    for node_id in storage_pointer_references {
                        if let Some(node) = self.context.nodes.get(node_id) {
                            let loc_info = self.context.get_node_sort_key(node);
                            writeln!(f, "\t <> {:?}", (loc_info.1, loc_info.2))?;
                        }
                    }
                } else {
                    writeln!(f, "<unknown_node_id_{}>", state_variable_id)?;
                }
            }
            writeln!(f)?;
        }

        std::fmt::Result::Ok(())
    }
}

/// Interface to be used by other modules defined here.
impl<'a> ApproximateStorageChangeFinder<'a> {
    /// Initialize
    pub fn from<T: Node + ?Sized>(context: &'a WorkspaceContext, node: &T) -> Self {
        let mut extractor = ApproximateStorageChangeFinder {
            directly_manipulated_state_variables: BTreeSet::new(),
            manipulated_storage_pointers: BTreeSet::new(),
            state_variables_to_storage_pointers: BTreeMap::new(),
            context,
        };
        node.accept(&mut extractor).unwrap_or_default();
        extractor
    }

    pub fn state_variables_have_been_manipulated(&self) -> bool {
        !self.directly_manipulated_state_variables.is_empty()
            || !self.manipulated_storage_pointers.is_empty()
    }

    pub fn no_state_variable_has_been_manipulated(&self) -> bool {
        self.directly_manipulated_state_variables.is_empty()
            && self.manipulated_storage_pointers.is_empty()
    }

    pub fn fetch_non_exhaustive_manipulated_state_variables(&self) -> Vec<&VariableDeclaration> {
        let mut manipulated_state_vars: BTreeSet<NodeID> = BTreeSet::new();
        manipulated_state_vars.extend(self.directly_manipulated_state_variables.iter());
        for (state_variable_id, storage_pointers) in self.state_variables_to_storage_pointers.iter()
        {
            if storage_pointers.iter().any(|ptr| self.manipulated_storage_pointers.contains(ptr)) {
                manipulated_state_vars.insert(*state_variable_id);
            }
        }
        manipulated_state_vars
            .into_iter()
            .flat_map(|v| self.context.nodes.get(&v))
            .flat_map(|n| {
                if let ASTNode::VariableDeclaration(variable_declaration) = n {
                    assert!(variable_declaration.state_variable);
                    return Some(variable_declaration);
                }
                None
            })
            .collect()
    }

    pub fn state_variable_has_been_manipulated(&self, var: &VariableDeclaration) -> Option<bool> {
        if self.directly_manipulated_state_variables.contains(&var.id) {
            return Some(true);
        }
        if self.manipulated_storage_pointers.is_empty() {
            return Some(false);
        }
        // Now use our heuristics
        if self.state_variables_to_storage_pointers.get(&var.id).is_some_and(|entry| {
            entry.iter().any(|e| self.manipulated_storage_pointers.contains(e))
        }) {
            return Some(true);
        }

        // At this point, we don't know if any of the storage pointers refer to [`var`], so we
        // cannot say for sure, if it has been manipulated or not.
        None
    }

    pub fn state_variable_has_not_been_manipulated(
        &self,
        var: &VariableDeclaration,
    ) -> Option<bool> {
        if self.directly_manipulated_state_variables.contains(&var.id) {
            return Some(false);
        }
        if self.manipulated_storage_pointers.is_empty() {
            return Some(true);
        }
        // Now use our heuristics
        if self.state_variables_to_storage_pointers.get(&var.id).is_some_and(|entry| {
            entry.iter().any(|e| self.manipulated_storage_pointers.contains(e))
        }) {
            return Some(false);
        }

        // At this point, we don't know if any of the storage pointers refer to [`var`], so we
        // cannot say for sure, if it has been manipulated or not.
        None
    }
}

impl ASTConstVisitor for ApproximateStorageChangeFinder<'_> {
    fn visit_unary_operation(&mut self, node: &UnaryOperation) -> Result<bool> {
        // WRITE HEURISTICS
        // Catch unary operations that manipulate variables
        if node.operator == "delete" || node.operator == "++" || node.operator == "--" {
            for id in find_base(node.sub_expression.as_ref()).0 {
                match is_storage_variable_or_storage_pointer(self.context, id) {
                    Some(AssigneeType::StateVariable) => {
                        self.directly_manipulated_state_variables.insert(id);
                    }
                    Some(AssigneeType::StorageLocationVariable) => {
                        self.manipulated_storage_pointers.insert(id);
                    }
                    None => {}
                };
            }
        }

        Ok(true)
    }

    fn visit_member_access(&mut self, member: &MemberAccess) -> Result<bool> {
        if !member.expression.type_descriptions().is_some_and(|type_desc| {
            type_desc.type_string.as_ref().is_some_and(|type_string| {
                type_string.ends_with("[] storage ref")
                    || type_string.ends_with("[] storage pointer")
            })
        }) {
            return Ok(true);
        }

        let (base_variable_ids, _) = find_base(member.expression.as_ref());
        // assert!(base_variable_ids.len() == 1);

        // WRITE HEURISTICS
        if member.member_name == "push" || member.member_name == "pop" {
            for id in base_variable_ids.iter() {
                match is_storage_variable_or_storage_pointer(self.context, *id) {
                    Some(AssigneeType::StateVariable) => {
                        self.directly_manipulated_state_variables.insert(*id);
                    }
                    Some(AssigneeType::StorageLocationVariable) => {
                        self.manipulated_storage_pointers.insert(*id);
                    }
                    None => {}
                };
            }
        }

        Ok(true)
    }

    fn visit_assignment(&mut self, assignment: &Assignment) -> Result<bool> {
        let (base_variable_lhs_ids, type_strings) = find_base(assignment.left_hand_side.as_ref());
        let (base_variable_rhs_ids, _) = find_base(assignment.right_hand_side.as_ref());

        for (id, type_string) in zip(base_variable_lhs_ids.iter(), type_strings.iter()) {
            // When something is assigned to an expression of type "storage pointer", no state
            // variable's value changes. The only value changed is the thing which the
            // storage pointer points to. The value of a storage variable changes if the
            // expression's type string contains "storage ref" in case of structs, arrays, etc

            if type_string.ends_with("storage pointer") {
                continue;
            }

            match is_storage_variable_or_storage_pointer(self.context, *id) {
                Some(AssigneeType::StateVariable) => {
                    self.directly_manipulated_state_variables.insert(*id);
                }
                Some(AssigneeType::StorageLocationVariable) => {
                    self.manipulated_storage_pointers.insert(*id);
                }
                None => {}
            };
        }

        // Now, on a separate note, let's look for a heuristic to link up state variables with
        // storage pointers. But here, we only handle the cases when there are equal number
        // of elements on either side of `=` . This allows us to assume 1:1 relationship.
        if base_variable_lhs_ids.len() == base_variable_rhs_ids.len() {
            for (lhs_id, rhs_id) in zip(base_variable_lhs_ids, base_variable_rhs_ids) {
                if let (
                    Some(AssigneeType::StorageLocationVariable),
                    Some(AssigneeType::StateVariable),
                ) = (
                    is_storage_variable_or_storage_pointer(self.context, lhs_id),
                    is_storage_variable_or_storage_pointer(self.context, rhs_id),
                ) {
                    match self.state_variables_to_storage_pointers.entry(rhs_id) {
                        std::collections::btree_map::Entry::Vacant(v) => {
                            v.insert(BTreeSet::from_iter([lhs_id]));
                        }
                        std::collections::btree_map::Entry::Occupied(mut o) => {
                            (*o.get_mut()).insert(lhs_id);
                        }
                    };
                }
            }
        }

        // READ HEURISTICS
        // Pretty much the same logic as described in `visit_variable_declaration_statement`
        //

        // let (left_node_ids, _) = find_base(assignment.left_hand_side.as_ref());
        // let right_node_ids = flatten_expression(assignment.right_hand_side.as_ref());

        // See if it's a 1:1 relationship. Only then, proceed. Later, we can think of heuristics to
        // handle x:y (but likely we will have to rely on a dependency graph for that. Case:
        // `(x, y) = func()` is out of scope for this).
        //
        // When it comes to tracking WRITEs, it doesn't matter what's on RHS of `=`
        // When it comes to tracking READs, it does! If the LHS type is storage then you are simply
        // carrying a reference at compile time, you are not actually reading. Whereas, if
        // the LHS is memory, you are performing "sload"! But again, this logic changes
        // based on type of value in RHS. If it's a function call you should look at
        // return values and nature of the corresponding variable where that value will be stored.
        // Likewise, different for different nodes albeit identifier one is probably the
        // most straightforward if left_node_ids.len() == right_node_ids.len() {}

        Ok(true)
    }

    // For heurstics: Try to link up as much storage pointers and state variables as possible
    fn visit_variable_declaration_statement(
        &mut self,
        node: &VariableDeclarationStatement,
    ) -> Result<bool> {
        if let Some(initial_value) = node.initial_value.as_ref() {
            let corresponding_variable_declaration_ids = node
                .declarations
                .iter()
                .map(|v| {
                    if let Some(variable_declaration) = v {
                        variable_declaration.id
                    } else {
                        i64::MIN
                    }
                })
                .collect::<Vec<_>>();
            let initial_value_node_ids = flatten_expression(initial_value); // For READ heuristics
            let (initial_value_bases, _) = find_base(initial_value); // For LINK heuristics

            // Let's first support 1:1 relationships only
            if corresponding_variable_declaration_ids.len() == initial_value_node_ids.len() {
                let common_len = corresponding_variable_declaration_ids.len();

                // This for loop takes care of recording instances in VDS (Var Decl Stmnt) where
                // there is a read from the storage.
                //
                //  READ HEURISTICS
                //
                // TODO: Write tests for these
                // Then creates `passes_read_check()` before matching the var id on extracting
                // reference declarations Then replicate the logic for assignments
                // use lvaluerequested = false and islvalue = true to check if it's being read
                // in case of visiting indexaccess, memberaccess, etc (expr_node! variants)
                // So that it can detect stuff outside of just assignments. Example -
                // functionCall(a.b) where a is state var (Technically you are
                // reading a.b's value to make that function call)
                //
                // for i in 0..common_len {
                //     let variable_declaration_id = corresponding_variable_declaration_ids[i];
                //     let corresponding_initial_value_id = initial_value_node_ids[i];

                //     if is_storage_variable_or_storage_pointer(
                //         &self.context,
                //         variable_declaration_id,
                //     )
                //     .is_some()
                //     {
                //         // If we are not assigning something to a storage pointer or a storage
                // reference, that means         // we're storing it in memory.
                // Therefore, we can consider that the corresponding initialValue
                //         // is being "read". Otherwise we are just creating pointers, not
                // "sload"ing.         continue;
                //     }

                //     if let Some(node) = self.context.nodes.get(&corresponding_initial_value_id) {
                //         // In case of internal function call, it's complex to analyze
                //         if node.node_type() != NodeType::FunctionCall || it is{
                //             let referenced_declarations =
                //                 ExtractReferencedDeclarations::from(node).extracted;

                //             for variable_id in referenced_declarations {
                //                 match is_storage_variable_or_storage_pointer(
                //                     self.context,
                //                     variable_id,
                //                 ) {
                //                     // Assumption: At this point in code we know that it could be
                // a storage pointer/variable that represents                     //
                // uint, bool, array element, etc. so it's technically being read.
                //                     Some(AssigneeType::StateVariable) => {
                //                         self.directly_read_state_variables.insert(variable_id);
                //                     }
                //                     Some(AssigneeType::StorageLocationVariable) => {
                //                         self.read_storage_pointers.insert(variable_id);
                //                     }
                //                     None => {}
                //                 }
                //             }
                //         }
                //     }
                // }

                assert!(initial_value_bases.len() == common_len);

                // LINK heuristics
                for i in 0..common_len {
                    let variable_declaration_id = corresponding_variable_declaration_ids[i];
                    let corresponding_initial_value_base_id = initial_value_bases[i];

                    if let (
                        Some(AssigneeType::StorageLocationVariable),
                        Some(AssigneeType::StateVariable),
                    ) = (
                        is_storage_variable_or_storage_pointer(
                            self.context,
                            variable_declaration_id,
                        ),
                        is_storage_variable_or_storage_pointer(
                            self.context,
                            corresponding_initial_value_base_id,
                        ),
                    ) {
                        match self
                            .state_variables_to_storage_pointers
                            .entry(corresponding_initial_value_base_id)
                        {
                            std::collections::btree_map::Entry::Vacant(v) => {
                                v.insert(BTreeSet::from_iter([variable_declaration_id]));
                            }
                            std::collections::btree_map::Entry::Occupied(mut o) => {
                                (*o.get_mut()).insert(variable_declaration_id);
                            }
                        };
                    }
                }
            }
        }

        Ok(true)
    }
}

fn flatten_expression(expr: &Expression) -> Vec<NodeID> {
    let mut node_ids = vec![];
    match expr {
        Expression::TupleExpression(TupleExpression { components, .. }) => {
            for component in components.iter().flatten() {
                let component_node_ids = flatten_expression(component);
                node_ids.extend(component_node_ids);
            }
        }
        _ => {
            node_ids.push(expr.get_node_id().unwrap_or(i64::MIN));
        }
    }
    node_ids
}

fn find_base(expr: &Expression) -> (Vec<NodeID>, Vec<String>) {
    let mut node_ids = vec![];
    let mut type_strings = vec![];
    match expr {
        Expression::Identifier(Identifier {
            referenced_declaration: Some(id),
            type_descriptions: TypeDescriptions { type_string: Some(type_string), .. },
            ..
        }) => {
            node_ids.push(*id);
            type_strings.push(type_string.clone());
        }
        // Handle mappings assignment
        Expression::IndexAccess(IndexAccess {
            base_expression,
            type_descriptions: TypeDescriptions { type_string: Some(type_string), .. },
            ..
        }) => {
            node_ids.extend(find_base(base_expression.as_ref()).0);
            type_strings.push(type_string.clone());
        }
        // Handle struct member assignment
        Expression::MemberAccess(MemberAccess {
            expression,
            type_descriptions: TypeDescriptions { type_string: Some(type_string), .. },
            ..
        }) => {
            node_ids.extend(find_base(expression.as_ref()).0);
            type_strings.push(type_string.clone());
        }
        // Handle tuple form lhs while assigning
        Expression::TupleExpression(TupleExpression { components, .. }) => {
            for component in components.iter() {
                if let Some(component) = component {
                    let (component_node_ids, component_type_strings) = find_base(component);
                    node_ids.extend(component_node_ids);
                    type_strings.extend(component_type_strings);
                } else {
                    node_ids.push(i64::MIN);
                    type_strings.push(String::from("irrelevant"));
                }
            }
        }
        // Handle assignment with values like ++i, --j, i++, etc
        Expression::UnaryOperation(UnaryOperation {
            sub_expression,
            type_descriptions: TypeDescriptions { type_string: Some(type_string), .. },
            ..
        }) => {
            node_ids.extend(find_base(sub_expression.as_ref()).0);
            type_strings.push(type_string.clone());
        }
        _ => {
            node_ids.push(i64::MIN);
            type_strings.push(String::from("irrelevant"));
        }
    };
    assert_eq!(node_ids.len(), type_strings.len());
    (node_ids, type_strings)
}

#[derive(PartialEq)]
enum AssigneeType {
    StateVariable,
    StorageLocationVariable,
}

fn is_storage_variable_or_storage_pointer(
    context: &WorkspaceContext,
    node_id: NodeID,
) -> Option<AssigneeType> {
    let node = context.nodes.get(&node_id)?;
    if let ASTNode::VariableDeclaration(variable) = node {
        if variable.storage_location == StorageLocation::Transient {
            return None;
        }
        // Assumption
        // variable.state_variable is true when it's an actual state variable
        // variable.storage_location is StorageLocation::Storage when it's a storage reference
        // pointer
        if variable.state_variable {
            return Some(AssigneeType::StateVariable);
        } else if variable.storage_location == StorageLocation::Storage {
            return Some(AssigneeType::StorageLocationVariable);
        }
    }
    None
}

#[cfg(test)]
mod approximate_storage_change_finder_tests {
    use crate::detect::test_utils::load_solidity_source_unit;

    use super::ApproximateStorageChangeFinder;

    #[test]

    fn has_variable_declarations() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/StateVariablesManipulation.sol",
        );

        assert!(!context.variable_declarations().is_empty());
    }

    #[test]

    fn test_no_state_variable_manipulations_found() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/StateVariablesManipulation.sol",
        );

        let contract = context.find_contract_by_name("NoStateVarManipulationExample");
        let func = contract.find_function_by_name("dontManipulateStateVar");

        let finder = ApproximateStorageChangeFinder::from(&context, func);
        let no_changes_found = !finder.state_variables_have_been_manipulated();
        println!("NoStateVarManipulationExample::dontManipulateStateVar()\n{:?}", finder);
        println!("{:?}", finder);
        assert!(no_changes_found);
    }

    #[test]

    fn test_simple_state_variable_manipulations_found() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/StateVariablesManipulation.sol",
        );

        let contract = context.find_contract_by_name("SimpleStateVarManipulationExample");
        let func = contract.find_function_by_name("manipulateStateVarDirectly");
        let func2 = contract.find_function_by_name("readSimpleStateVars");

        let finder = ApproximateStorageChangeFinder::from(&context, func);
        let changes_found = finder.state_variables_have_been_manipulated();
        println!("SimpleStateVarManipulationExample::manipulateStateVarDirectly()\n{:?}", finder);
        assert!(changes_found);
        assert_eq!(finder.directly_manipulated_state_variables.len(), 5);
        assert!(finder.manipulated_storage_pointers.is_empty());

        let finder = ApproximateStorageChangeFinder::from(&context, func2);
        let changes_found = finder.state_variables_have_been_manipulated();
        println!("SimpleStateVarManipulationExample::readSimpleStateVars()\n{:?}", finder);
        assert!(!changes_found);
        assert!(finder.directly_manipulated_state_variables.is_empty());
        assert!(finder.manipulated_storage_pointers.is_empty());
    }

    #[test]

    fn test_fixed_size_array_assignments() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/StateVariablesManipulation.sol",
        );

        let contract = context.find_contract_by_name("FixedSizeArraysAssignmentExample");

        let func1 = contract.find_function_by_name("manipulateDirectly");
        let func2 = contract.find_function_by_name("manipulateViaIndexAccess");

        // Test manipulateDirectly() function

        let finder = ApproximateStorageChangeFinder::from(&context, func1);
        println!("FixedSizeArraysAssignmentExample::manipulateDirectly()\n{:?}", finder);

        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.directly_manipulated_state_variables.len(), 1);
        assert!(finder.manipulated_storage_pointers.is_empty());

        // Test manipulateViaIndexAccess() function

        let finder = ApproximateStorageChangeFinder::from(&context, func2);
        println!("FixedSizeArraysAssignmentExample::manipulateViaIndexAccess()\n{:?}", finder);

        let changes_found2 = finder.state_variables_have_been_manipulated();
        assert!(changes_found2);
        assert_eq!(finder.directly_manipulated_state_variables.len(), 2);
        assert!(finder.manipulated_storage_pointers.is_empty());
    }

    #[test]

    fn test_struct_plus_fixed_array_assignment_example() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/StateVariablesManipulation.sol",
        );

        let contract = context.find_contract_by_name("StructPlusFixedArrayAssignmentExample");

        let func = contract.find_function_by_name("manipulateStateVariables");
        let func2 = contract.find_function_by_name("manipulateStateVariables2");
        let func3 = contract.find_function_by_name("manipulateStateVariables3");
        let func4 = contract.find_function_by_name("manipulateStateVariables4");
        let func5 = contract.find_function_by_name("manipulateStateVariables5");
        let func6 = contract.find_function_by_name("manipulateStateVariables6");
        let func7 = contract.find_function_by_name("manipulateStateVariables7");
        let func8 = contract.find_function_by_name("manipulateStateVariables8");
        let func_helper = contract.find_function_by_name("manipulateHelper");

        // Test manipulateStateVariables
        let finder = ApproximateStorageChangeFinder::from(&context, func);
        println!("StructPlusFixedArrayAssignmentExample::manipulateStateVariables()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.directly_manipulated_state_variables.len(), 3);
        assert!(finder.manipulated_storage_pointers.is_empty());

        // Test manipulateStateVariables2
        let finder = ApproximateStorageChangeFinder::from(&context, func2);
        println!(
            "StructPlusFixedArrayAssignmentExample::manipulateStateVariables2()\n{:?}",
            finder
        );
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.manipulated_storage_pointers.len(), 1);
        assert_eq!(
            finder
                .state_variables_to_storage_pointers
                .get(&contract.find_state_variable_node_id_by_name("person3"))
                .unwrap()
                .len(),
            1
        );
        assert_eq!(
            finder
                .state_variables_to_storage_pointers
                .get(&contract.find_state_variable_node_id_by_name("persons"))
                .unwrap()
                .len(),
            1
        );
        assert!(finder.directly_manipulated_state_variables.is_empty());

        // Test manipulateStateVariables3
        let finder = ApproximateStorageChangeFinder::from(&context, func3);
        println!(
            "StructPlusFixedArrayAssignmentExample::manipulateStateVariables3()\n{:?}",
            finder
        );
        let no_changes_found = !finder.state_variables_have_been_manipulated();
        assert!(no_changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert!(finder.directly_manipulated_state_variables.is_empty());
        assert_eq!(finder.state_variables_to_storage_pointers.len(), 1); // person3 links to ptr_person3
        assert_eq!(
            finder
                .state_variables_to_storage_pointers
                .get(&contract.find_state_variable_node_id_by_name("person3"))
                .unwrap()
                .len(),
            1
        );

        // Test manipulateStateVariables4
        let finder = ApproximateStorageChangeFinder::from(&context, func4);
        println!(
            "StructPlusFixedArrayAssignmentExample::manipulateStateVariables4()\n{:?}",
            finder
        );
        let no_changes_found = !finder.state_variables_have_been_manipulated();
        assert!(no_changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert!(finder.directly_manipulated_state_variables.is_empty());

        // Test manipulateStateVariables5
        let finder = ApproximateStorageChangeFinder::from(&context, func5);
        println!(
            "StructPlusFixedArrayAssignmentExample::manipulateStateVariables5()\n{:?}",
            finder
        );
        let no_changes_found = !finder.state_variables_have_been_manipulated();
        assert!(no_changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert!(finder.directly_manipulated_state_variables.is_empty());
        assert_eq!(finder.state_variables_to_storage_pointers.len(), 1);
        assert_eq!(
            finder
                .state_variables_to_storage_pointers
                .get(&contract.find_state_variable_node_id_by_name("person3"))
                .unwrap()
                .len(),
            1
        );

        // Test funcHelper
        let finder = ApproximateStorageChangeFinder::from(&context, func_helper);
        println!("StructPlusFixedArrayAssignmentExample::manipulateHelper()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.manipulated_storage_pointers.len(), 2);
        assert!(finder.directly_manipulated_state_variables.is_empty());
        assert_eq!(
            finder
                .state_variables_to_storage_pointers
                .get(&contract.find_state_variable_node_id_by_name("person3"))
                .unwrap()
                .len(),
            1
        );

        // Test manipulateStateVariables6
        let finder = ApproximateStorageChangeFinder::from(&context, func6);
        println!(
            "StructPlusFixedArrayAssignmentExample::manipulateStateVariables6()\n{:?}",
            finder
        );
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.manipulated_storage_pointers.len(), 2);
        assert!(finder.directly_manipulated_state_variables.is_empty());
        assert_eq!(
            finder
                .state_variables_to_storage_pointers
                .get(&contract.find_state_variable_node_id_by_name("person3"))
                .unwrap()
                .len(),
            4
        );

        // Test manipulateStateVariables7
        let finder = ApproximateStorageChangeFinder::from(&context, func7);
        println!(
            "StructPlusFixedArrayAssignmentExample::manipulateStateVariables7()\n{:?}",
            finder
        );
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert_eq!(finder.directly_manipulated_state_variables.len(), 3);

        // Test manipulateStateVariables8
        let finder = ApproximateStorageChangeFinder::from(&context, func8);
        println!(
            "StructPlusFixedArrayAssignmentExample::manipulateStateVariables8()\n{:?}",
            finder
        );
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert_eq!(finder.directly_manipulated_state_variables.len(), 2);
    }

    #[test]

    fn test_sv_manipulation_library() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/StateVariablesManipulation.sol",
        );

        let contract = context.find_contract_by_name("SVManipulationLibrary");

        let func = contract.find_function_by_name("manipulateLib");
        let func2 = contract.find_function_by_name("manipulateLib2");
        let func3 = contract.find_function_by_name("manipulateLib3");

        // Test manipulateLib()
        let finder = ApproximateStorageChangeFinder::from(&context, func);
        println!("SVManipulationLibrary::manipulateLib()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.manipulated_storage_pointers.len(), 1);
        assert!(finder.directly_manipulated_state_variables.is_empty());

        // Test manipulateLib2()
        let finder = ApproximateStorageChangeFinder::from(&context, func2);
        println!("SVManipulationLibrary::manipulateLib2()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.manipulated_storage_pointers.len(), 1);
        assert!(finder.directly_manipulated_state_variables.is_empty());

        // Test manipulateLib3()
        let finder = ApproximateStorageChangeFinder::from(&context, func3);
        println!("SVManipulationLibrary::manipulateLib3()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.manipulated_storage_pointers.len(), 2);
        assert!(finder.directly_manipulated_state_variables.is_empty());
    }

    #[test]

    fn test_no_struct_plus_fixed_array_assignment_example() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/StateVariablesManipulation.sol",
        );

        let contract = context.find_contract_by_name("NoStructPlusFixedArrayAssignmentExample");

        let func = contract.find_function_by_name("dontManipulateStateVariables");
        let func2 = contract.find_function_by_name("dontManipulateStateVariablesPart2");
        let func3 = contract.find_function_by_name("dontManipulateStateVariablesPart3");
        let func4 = contract.find_function_by_name("dontManipulateStateVariablesPart4");
        let func5 = contract.find_function_by_name("dontManipulateStateVariablesPart5");

        // Test dontManipulateStateVariables()
        let finder = ApproximateStorageChangeFinder::from(&context, func);
        println!(
            "NoStructPlusFixedArrayAssignmentExample::dontManipulateStateVariables()\n{:?}",
            finder
        );
        let no_changes_found = !finder.state_variables_have_been_manipulated();
        assert!(no_changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert!(finder.directly_manipulated_state_variables.is_empty());

        // Test dontManipulateStateVariablesPart2()
        let finder = ApproximateStorageChangeFinder::from(&context, func2);
        println!(
            "NoStructPlusFixedArrayAssignmentExample::dontManipulateStateVariablesPart2()\n{:?}",
            finder
        );
        let no_changes_found = !finder.state_variables_have_been_manipulated();
        assert!(no_changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert!(finder.directly_manipulated_state_variables.is_empty());

        // Test dontManipulateStateVariablesPart3()
        let finder = ApproximateStorageChangeFinder::from(&context, func3);
        println!(
            "NoStructPlusFixedArrayAssignmentExample::dontManipulateStateVariablesPart3()\n{:?}",
            finder
        );
        let no_changes_found = !finder.state_variables_have_been_manipulated();
        assert!(no_changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert!(finder.directly_manipulated_state_variables.is_empty());

        // Test dontManipulateStateVariablesPart4()
        let finder = ApproximateStorageChangeFinder::from(&context, func4);
        println!(
            "NoStructPlusFixedArrayAssignmentExample::dontManipulateStateVariablesPart4()\n{:?}",
            finder
        );
        let no_changes_found = !finder.state_variables_have_been_manipulated();
        assert!(no_changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert!(finder.directly_manipulated_state_variables.is_empty());

        // Test dontManipulateStateVariablesPart4()
        let finder = ApproximateStorageChangeFinder::from(&context, func5);
        println!(
            "NoStructPlusFixedArrayAssignmentExample::dontManipulateStateVariablesPart5()\n{:?}",
            finder
        );
        let no_changes_found = !finder.state_variables_have_been_manipulated();
        assert!(no_changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert!(finder.directly_manipulated_state_variables.is_empty());
    }

    #[test]

    fn test_dynamic_array_push_changes() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/StateVariablesManipulation.sol",
        );

        let contract = context.find_contract_by_name("DynamicArraysPushExample");

        let func = contract.find_function_by_name("manipulateDirectly");
        let func2 = contract.find_function_by_name("manipulateViaIndexAccess");
        let func3 = contract.find_function_by_name("manipulateViaMemberAccess");
        let func4 = contract.find_function_by_name("manipulateViaMemberAccess2");

        // Test manipulateDirectly()
        let finder = ApproximateStorageChangeFinder::from(&context, func);
        println!("DynamicArraysPushExample::manipulateDirectly()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert_eq!(finder.directly_manipulated_state_variables.len(), 1);

        // Test manipulateViaIndexAccess()
        let finder = ApproximateStorageChangeFinder::from(&context, func2);
        println!("DynamicArraysPushExample::manipulateViaIndexAccess()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert_eq!(finder.directly_manipulated_state_variables.len(), 3);

        // Test manipulateViaMemberAccess()
        let finder = ApproximateStorageChangeFinder::from(&context, func3);
        println!("DynamicArraysPushExample::manipulateViaMemberAccess()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert!(finder.manipulated_storage_pointers.is_empty());
        assert_eq!(finder.directly_manipulated_state_variables.len(), 1);

        // Test manipulateViaMemberAccess2()
        let finder = ApproximateStorageChangeFinder::from(&context, func4);
        println!("DynamicArraysPushExample::manipulateViaMemberAccess2()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.manipulated_storage_pointers.len(), 1); // we only want to capture p1
        assert!(finder.directly_manipulated_state_variables.is_empty());
    }

    #[test]

    fn test_dynamic_mappings_array_push_changes() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/StateVariablesManipulation.sol",
        );

        let contract = context.find_contract_by_name("DynamicMappingsArrayPushExample");
        let func = contract.find_function_by_name("add");

        // Test add()
        let finder = ApproximateStorageChangeFinder::from(&context, func);
        println!("DynamicMappingsArrayPushExample::add()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.directly_manipulated_state_variables.len(), 1);
        assert!(finder.manipulated_storage_pointers.is_empty());
    }

    #[test]

    fn test_fixed_size_arrays_deletion_example() {
        let context = load_solidity_source_unit(
            "../tests/contract-playground/src/StateVariablesManipulation.sol",
        );

        let contract = context.find_contract_by_name("FixedSizeArraysDeletionExample");
        let func = contract.find_function_by_name("manipulateDirectly");
        let func2 = contract.find_function_by_name("manipulateViaIndexAccess");

        // Test func()
        let finder = ApproximateStorageChangeFinder::from(&context, func);
        println!("FixedSizeArraysDeletionExample::manipulateDirectly()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.directly_manipulated_state_variables.len(), 1);
        assert!(finder.manipulated_storage_pointers.is_empty());

        // Test func2()
        let finder = ApproximateStorageChangeFinder::from(&context, func2);
        println!("FixedSizeArraysDeletionExample::manipulateViaIndexAccess()\n{:?}", finder);
        let changes_found = finder.state_variables_have_been_manipulated();
        assert!(changes_found);
        assert_eq!(finder.directly_manipulated_state_variables.len(), 2);
        assert!(finder.manipulated_storage_pointers.is_empty());
    }
}

```
Page 89/94FirstPrevNextLast