This is page 98 of 103. Use http://codebase.md/cyfrin/aderyn?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .cargo
│ └── config.toml
├── .git-blame-ignore-revs
├── .gitattributes
├── .github
│ ├── images
│ │ ├── aderyn_logo.png
│ │ ├── poweredbycyfrinblack.png
│ │ └── poweredbycyfrinblue.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ ├── false_positive_issue.md
│ │ └── feature_request.md
│ └── workflows
│ ├── cargo.yml
│ ├── dependencies.yml
│ ├── release.yml
│ ├── reports.yml
│ └── toml.yml
├── .gitignore
├── .gitmodules
├── .vscode
│ └── settings.json
├── aderyn
│ ├── Cargo.toml
│ ├── oranda.json
│ ├── README.md
│ ├── src
│ │ ├── birdsong.rs
│ │ ├── completions.rs
│ │ ├── lib.rs
│ │ ├── lsp.rs
│ │ ├── main.rs
│ │ ├── mcp.rs
│ │ └── panic.rs
│ └── templates
│ └── aderyn.toml
├── aderyn_core
│ ├── .gitignore
│ ├── Cargo.toml
│ ├── README.md
│ ├── src
│ │ ├── ast
│ │ │ ├── ast_nodes.rs
│ │ │ ├── ast.rs
│ │ │ ├── impls
│ │ │ │ ├── ctx
│ │ │ │ │ ├── utils.rs
│ │ │ │ │ └── workspace.rs
│ │ │ │ ├── ctx.rs
│ │ │ │ ├── disp
│ │ │ │ │ ├── blocks.rs
│ │ │ │ │ ├── contracts.rs
│ │ │ │ │ ├── enumerations.rs
│ │ │ │ │ ├── errors.rs
│ │ │ │ │ ├── events.rs
│ │ │ │ │ ├── expressions.rs
│ │ │ │ │ ├── functions.rs
│ │ │ │ │ ├── identifiers.rs
│ │ │ │ │ ├── literals.rs
│ │ │ │ │ ├── modifiers.rs
│ │ │ │ │ ├── statements.rs
│ │ │ │ │ ├── structures.rs
│ │ │ │ │ ├── types.rs
│ │ │ │ │ ├── user_defined_value_types.rs
│ │ │ │ │ ├── using_for_directives.rs
│ │ │ │ │ └── variables.rs
│ │ │ │ ├── disp.rs
│ │ │ │ ├── node
│ │ │ │ │ ├── blocks.rs
│ │ │ │ │ ├── contracts.rs
│ │ │ │ │ ├── documentation.rs
│ │ │ │ │ ├── enumerations.rs
│ │ │ │ │ ├── errors.rs
│ │ │ │ │ ├── events.rs
│ │ │ │ │ ├── expressions.rs
│ │ │ │ │ ├── functions.rs
│ │ │ │ │ ├── identifiers.rs
│ │ │ │ │ ├── import_directives.rs
│ │ │ │ │ ├── literals.rs
│ │ │ │ │ ├── modifiers.rs
│ │ │ │ │ ├── pragma_directives.rs
│ │ │ │ │ ├── source_units.rs
│ │ │ │ │ ├── statements.rs
│ │ │ │ │ ├── structures.rs
│ │ │ │ │ ├── types.rs
│ │ │ │ │ ├── user_defined_value_types.rs
│ │ │ │ │ ├── using_for_directives.rs
│ │ │ │ │ └── variables.rs
│ │ │ │ ├── node.rs
│ │ │ │ ├── own
│ │ │ │ │ ├── hashing.rs
│ │ │ │ │ ├── node_id.rs
│ │ │ │ │ ├── source_units.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ └── own.rs
│ │ │ ├── impls.rs
│ │ │ ├── macros.rs
│ │ │ ├── magic.rs
│ │ │ ├── node_type.rs
│ │ │ └── yul.rs
│ │ ├── ast.rs
│ │ ├── audit
│ │ │ ├── attack_surface.rs
│ │ │ ├── auditor.rs
│ │ │ ├── entrypoint.rs
│ │ │ └── public_functions_no_sender.rs
│ │ ├── audit.rs
│ │ ├── context
│ │ │ ├── browser
│ │ │ │ ├── ancestral_line.rs
│ │ │ │ ├── closest_ancestor.rs
│ │ │ │ ├── external_calls.rs
│ │ │ │ ├── extractor.rs
│ │ │ │ ├── immediate_children.rs
│ │ │ │ ├── location.rs
│ │ │ │ ├── macros.rs
│ │ │ │ ├── parent.rs
│ │ │ │ ├── peek_over.rs
│ │ │ │ ├── peek_under.rs
│ │ │ │ ├── peek.rs
│ │ │ │ ├── siblings.rs
│ │ │ │ ├── sort_nodes.rs
│ │ │ │ └── storage_vars.rs
│ │ │ ├── browser.rs
│ │ │ ├── capturable.rs
│ │ │ ├── flow
│ │ │ │ ├── display.rs
│ │ │ │ ├── error.rs
│ │ │ │ ├── kind.rs
│ │ │ │ ├── primitives.rs
│ │ │ │ ├── reducibles.rs
│ │ │ │ ├── tests.rs
│ │ │ │ ├── utils.rs
│ │ │ │ ├── visualizer.rs
│ │ │ │ └── voids.rs
│ │ │ ├── flow.rs
│ │ │ ├── graph
│ │ │ │ ├── callgraph
│ │ │ │ │ ├── legacy.rs
│ │ │ │ │ ├── new.rs
│ │ │ │ │ ├── tests.rs
│ │ │ │ │ ├── utils.rs
│ │ │ │ │ └── visit.rs
│ │ │ │ ├── callgraph.rs
│ │ │ │ ├── preprocess
│ │ │ │ │ ├── legacy.rs
│ │ │ │ │ └── new.rs
│ │ │ │ ├── preprocess.rs
│ │ │ │ ├── traits.rs
│ │ │ │ └── utils.rs
│ │ │ ├── graph.rs
│ │ │ ├── macros.rs
│ │ │ ├── mcp
│ │ │ │ ├── callgraph
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ ├── callgraph.rs
│ │ │ │ ├── contract_surface
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── util.rs
│ │ │ │ ├── contract_surface.rs
│ │ │ │ ├── list_contracts
│ │ │ │ │ ├── render.rs
│ │ │ │ │ └── tool.rs
│ │ │ │ ├── list_contracts.rs
│ │ │ │ ├── node_finder
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ ├── node_finder.rs
│ │ │ │ ├── node_summarizer
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ ├── node_summarizer.rs
│ │ │ │ ├── project_overview
│ │ │ │ │ ├── render.rs
│ │ │ │ │ └── tool.rs
│ │ │ │ ├── project_overview.rs
│ │ │ │ ├── tool_guide
│ │ │ │ │ └── tool.rs
│ │ │ │ └── tool_guide.rs
│ │ │ ├── mcp.rs
│ │ │ ├── router
│ │ │ │ ├── external_calls.rs
│ │ │ │ ├── internal_calls.rs
│ │ │ │ ├── modifier_calls.rs
│ │ │ │ └── tests.rs
│ │ │ ├── router.rs
│ │ │ └── workspace.rs
│ │ ├── context.rs
│ │ ├── detect
│ │ │ ├── detector.rs
│ │ │ ├── entrypoint.rs
│ │ │ ├── helpers.rs
│ │ │ ├── high
│ │ │ │ ├── _template.rs
│ │ │ │ ├── abi_encode_packed_hash_collision.rs
│ │ │ │ ├── arbitrary_transfer_from.rs
│ │ │ │ ├── const_func_changes_state.rs
│ │ │ │ ├── contract_locks_ether.rs
│ │ │ │ ├── dangerous_unary_operator.rs
│ │ │ │ ├── delegate_call_unchecked_address.rs
│ │ │ │ ├── delete_nested_mapping.rs
│ │ │ │ ├── dynamic_array_length_assignment.rs
│ │ │ │ ├── enumerable_loop_removal.rs
│ │ │ │ ├── eth_send_unchecked_address.rs
│ │ │ │ ├── experimental_encoder.rs
│ │ │ │ ├── function_selector_collision.rs
│ │ │ │ ├── incorrect_caret_operator.rs
│ │ │ │ ├── incorrect_erc20_interface.rs
│ │ │ │ ├── incorrect_erc721_interface.rs
│ │ │ │ ├── incorrect_shift_order.rs
│ │ │ │ ├── misused_boolean.rs
│ │ │ │ ├── msg_value_in_loops.rs
│ │ │ │ ├── multiple_constructors.rs
│ │ │ │ ├── nested_struct_in_mapping.rs
│ │ │ │ ├── out_of_order_retryable.rs
│ │ │ │ ├── pre_declared_variable_usage.rs
│ │ │ │ ├── reentrancy_state_change.rs
│ │ │ │ ├── reused_contract_name.rs
│ │ │ │ ├── rtlo.rs
│ │ │ │ ├── selfdestruct.rs
│ │ │ │ ├── signed_integer_storage_array.rs
│ │ │ │ ├── state_variable_shadowing.rs
│ │ │ │ ├── storage_array_memory_edit.rs
│ │ │ │ ├── strict_equality_contract_balance.rs
│ │ │ │ ├── tautological_compare.rs
│ │ │ │ ├── tautology_or_contradiction.rs
│ │ │ │ ├── tx_origin_used_for_auth.rs
│ │ │ │ ├── unchecked_low_level_call.rs
│ │ │ │ ├── unchecked_send.rs
│ │ │ │ ├── unprotected_initializer.rs
│ │ │ │ ├── unsafe_casting.rs
│ │ │ │ ├── weak_randomness.rs
│ │ │ │ └── yul_return.rs
│ │ │ ├── high.rs
│ │ │ ├── low
│ │ │ │ ├── _template.rs
│ │ │ │ ├── assert_state_change.rs
│ │ │ │ ├── block_timestamp_deadline.rs
│ │ │ │ ├── boolean_equality.rs
│ │ │ │ ├── builtin_symbol_shadowing.rs
│ │ │ │ ├── centralization_risk.rs
│ │ │ │ ├── constant_function_contains_assembly.rs
│ │ │ │ ├── costly_loop.rs
│ │ │ │ ├── dead_code.rs
│ │ │ │ ├── delegatecall_in_loop.rs
│ │ │ │ ├── deprecated_oz_function.rs
│ │ │ │ ├── division_before_multiplication.rs
│ │ │ │ ├── ecrecover.rs
│ │ │ │ ├── empty_block.rs
│ │ │ │ ├── empty_require_revert.rs
│ │ │ │ ├── function_initializing_state.rs
│ │ │ │ ├── function_pointer_in_constructor.rs
│ │ │ │ ├── inconsistent_type_names.rs
│ │ │ │ ├── incorrect_modifier.rs
│ │ │ │ ├── internal_function_used_once.rs
│ │ │ │ ├── large_numeric_literal.rs
│ │ │ │ ├── literal_instead_of_constant.rs
│ │ │ │ ├── local_variable_shadowing.rs
│ │ │ │ ├── missing_inheritance.rs
│ │ │ │ ├── modifier_used_only_once.rs
│ │ │ │ ├── multiple_placeholders.rs
│ │ │ │ ├── non_reentrant_not_first.rs
│ │ │ │ ├── push_0_opcode.rs
│ │ │ │ ├── redundant_statement.rs
│ │ │ │ ├── require_revert_in_loop.rs
│ │ │ │ ├── return_bomb.rs
│ │ │ │ ├── solmate_safe_transfer_lib.rs
│ │ │ │ ├── state_change_without_event.rs
│ │ │ │ ├── state_no_address_check.rs
│ │ │ │ ├── state_variable_could_be_constant.rs
│ │ │ │ ├── state_variable_could_be_immutable.rs
│ │ │ │ ├── state_variable_read_external.rs
│ │ │ │ ├── storage_array_length_not_cached.rs
│ │ │ │ ├── todo.rs
│ │ │ │ ├── unchecked_return.rs
│ │ │ │ ├── uninitialized_local_variable.rs
│ │ │ │ ├── unsafe_erc20_operation.rs
│ │ │ │ ├── unsafe_oz_erc721_mint.rs
│ │ │ │ ├── unspecific_solidity_pragma.rs
│ │ │ │ ├── unused_error.rs
│ │ │ │ ├── unused_import.rs
│ │ │ │ ├── unused_public_function.rs
│ │ │ │ ├── unused_state_variable.rs
│ │ │ │ └── void_constructor.rs
│ │ │ ├── low.rs
│ │ │ └── test_utils.rs
│ │ ├── detect.rs
│ │ ├── lib.rs
│ │ ├── stats
│ │ │ ├── cloc.rs
│ │ │ ├── dbg_tips.txt
│ │ │ ├── ignore.rs
│ │ │ ├── token.rs
│ │ │ └── util.rs
│ │ ├── stats.rs
│ │ ├── test_utils
│ │ │ └── load_source_unit.rs
│ │ ├── test_utils.rs
│ │ ├── visitor
│ │ │ ├── ast_visitor.rs
│ │ │ ├── macros.rs
│ │ │ └── workspace_visitor.rs
│ │ └── visitor.rs
│ ├── templates
│ │ └── mcp-tool-response
│ │ ├── callgraph.md
│ │ ├── contract_surface.md
│ │ ├── list_contracts.md
│ │ ├── node_finder_get_all.md
│ │ ├── node_finder_grep.md
│ │ ├── node_finder_search.md
│ │ ├── node_summarizer.md
│ │ ├── project_overview.md
│ │ └── tool_guide.md
│ └── tests
│ ├── common
│ │ ├── ancestral_line.rs
│ │ ├── closest_ancestor.rs
│ │ ├── immediate_children.rs
│ │ ├── immediate_parent.rs
│ │ ├── mod.rs
│ │ ├── new_ast_nodes.rs
│ │ ├── peek_over.rs
│ │ └── sibling.rs
│ └── traversal.rs
├── aderyn_driver
│ ├── .gitignore
│ ├── benches
│ │ └── detectors.rs
│ ├── Cargo.toml
│ ├── README.md
│ ├── src
│ │ ├── compile.rs
│ │ ├── config.rs
│ │ ├── display.rs
│ │ ├── driver.rs
│ │ ├── interface
│ │ │ ├── json.rs
│ │ │ ├── lsp.rs
│ │ │ ├── markdown.rs
│ │ │ ├── mod.rs
│ │ │ ├── sarif.rs
│ │ │ ├── tables.rs
│ │ │ └── util.rs
│ │ ├── lib.rs
│ │ ├── mcp.rs
│ │ ├── process.rs
│ │ └── runner.rs
│ └── tests
│ └── astgen.rs
├── bacon.toml
├── benchmarks
│ ├── aderyn
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── iteration_times.svg
│ │ │ └── pdf.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── iteration_times_small.svg
│ │ ├── iteration_times.svg
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── relative_iteration_times_small.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── SD.svg
│ │ └── typical.svg
│ ├── arbitrary-transfer-from
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── avoid-abi-encode-packed
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── block-timestamp-deadline
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── centralization-risk
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── constants-instead-of-literals
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── delegate-call-in-loop
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── deprecated-oz-functions
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── ecrecover
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── empty-block
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── hello_world
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── inconsistent-type-names
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── large-numeric-literal
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── non-reentrant-before-others
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── push-zero-opcode
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── report
│ │ └── index.html
│ ├── require-with-string
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── solmate-safe-transfer-lib
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unindexed-events
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unprotected-initializer
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unsafe-erc20-functions
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unsafe-oz-erc721-mint
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unspecific-solidity-pragma
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── useless-internal-function
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── useless-modifier
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── useless-public-function
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ └── zero-address-check
│ ├── base
│ │ ├── benchmark.json
│ │ ├── estimates.json
│ │ ├── sample.json
│ │ └── tukey.json
│ ├── change
│ │ └── estimates.json
│ ├── new
│ │ ├── benchmark.json
│ │ ├── estimates.json
│ │ ├── sample.json
│ │ └── tukey.json
│ └── report
│ ├── both
│ │ ├── pdf.svg
│ │ └── regression.svg
│ ├── change
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ └── t-test.svg
│ ├── index.html
│ ├── MAD.svg
│ ├── mean.svg
│ ├── median.svg
│ ├── pdf_small.svg
│ ├── pdf.svg
│ ├── regression_small.svg
│ ├── regression.svg
│ ├── relative_pdf_small.svg
│ ├── relative_regression_small.svg
│ ├── SD.svg
│ ├── slope.svg
│ └── typical.svg
├── Cargo.lock
├── Cargo.toml
├── cli
│ ├── benchmarks.sh
│ └── reportgen.sh
├── CODEOWNERS
├── CONTRIBUTING.md
├── cyfrinup
│ ├── dynamic_script
│ └── why.md
├── deny.toml
├── dist-workspace.toml
├── funding.json
├── LICENSE
├── Makefile
├── package-lock.json
├── package.json
├── README.md
├── RELEASE_CHECKLIST.md
├── reports
│ ├── adhoc-sol-files-highs-only-report.json
│ ├── adhoc-sol-files-report.md
│ ├── ccip-functions-report.md
│ ├── empty_report.md
│ ├── hardhat-playground-report.md
│ ├── nft-report-icm.md
│ ├── nft-report.md
│ ├── prb-math-report.md
│ ├── report.json
│ ├── report.md
│ ├── report.sarif
│ ├── sablier-aderyn-toml-nested-root.md
│ ├── templegold-report.md
│ └── uniswap_profile.md
├── rust-toolchain.toml
├── rustfmt.toml
├── tests
│ ├── adhoc-sol-files
│ │ ├── aderyn.toml
│ │ ├── Counter.sol
│ │ ├── DemoASTNodes.sol
│ │ ├── Helper.sol
│ │ ├── InconsistentUints.sol
│ │ ├── inheritance
│ │ │ ├── ExtendedInheritance.sol
│ │ │ ├── IContractInheritance.sol
│ │ │ └── InheritanceBase.sol
│ │ ├── InternalFunctions.sol
│ │ ├── lib
│ │ │ └── ThisShouldBeExcluded.sol
│ │ ├── multiple-versions
│ │ │ ├── 0.4
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ ├── 0.5
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ ├── 0.6
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ ├── 0.7
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ └── 0.8
│ │ │ ├── A.sol
│ │ │ └── B.sol
│ │ ├── OnceModifierExample.sol
│ │ └── StateVariables.sol
│ ├── ast
│ │ ├── abstract_contract.json
│ │ ├── address_payable.json
│ │ ├── array_type_name.json
│ │ ├── ast-erc4626.json
│ │ ├── base_constructor_call.json
│ │ ├── bit_not.json
│ │ ├── call.json
│ │ ├── constructor.json
│ │ ├── contract_dep_order.json
│ │ ├── do_while.json
│ │ ├── documentation_1.json
│ │ ├── documentation_2.json
│ │ ├── documentation_3.json
│ │ ├── documentation_local_variable.json
│ │ ├── documentation_on_statements.json
│ │ ├── documentation_triple.json
│ │ ├── empty_block.json
│ │ ├── enum_value_declaration.json
│ │ ├── enum_value.json
│ │ ├── event_definition.json
│ │ ├── experimental_encoder_pragma.json
│ │ ├── fallback_and_reveice_ether.json
│ │ ├── fallback_payable.json
│ │ ├── fallback.json
│ │ ├── function_type.json
│ │ ├── function.json
│ │ ├── global_enum.json
│ │ ├── global_struct.json
│ │ ├── inheritance_specifier.json
│ │ ├── leave.json
│ │ ├── license.json
│ │ ├── long_type_name_binary_operation.json
│ │ ├── long_type_name_identifier.json
│ │ ├── loop.json
│ │ ├── mappings.json
│ │ ├── modifier_definition.json
│ │ ├── modifier_invocation.json
│ │ ├── mutability.json
│ │ ├── nested_functions.json
│ │ ├── non_utf8.json
│ │ ├── override.json
│ │ ├── placeholder_statement.json
│ │ ├── receive_ether.json
│ │ ├── short_type_name_ref.json
│ │ ├── short_type_name.json
│ │ ├── slot_offset.json
│ │ ├── smoke.json
│ │ ├── source_location.json
│ │ ├── string.json
│ │ ├── stringlit.json
│ │ ├── switch_default.json
│ │ ├── switch.json
│ │ ├── try_catch.json
│ │ ├── two_base_functions.json
│ │ ├── unicode.json
│ │ ├── used_errors.json
│ │ ├── userDefinedValueType.json
│ │ ├── using_for_directive.json
│ │ ├── var_access.json
│ │ └── yul_hex_literal.json
│ ├── contract-playground
│ │ ├── .github
│ │ │ └── workflows
│ │ │ └── test.yml
│ │ ├── .gitignore
│ │ ├── dot
│ │ │ └── .gitkeep
│ │ ├── foundry.toml
│ │ ├── README.md
│ │ ├── script
│ │ │ └── Counter.s.sol
│ │ ├── src
│ │ │ ├── AbstractContract.sol
│ │ │ ├── AderynIgnoreCustomDetectors.sol
│ │ │ ├── AdminContract.sol
│ │ │ ├── ArbitraryTransferFrom.sol
│ │ │ ├── AssemblyExample.sol
│ │ │ ├── AssertStateChange.sol
│ │ │ ├── auditor_mode
│ │ │ │ ├── ExternalCalls.sol
│ │ │ │ └── PublicFunctionsWithoutSenderCheck.sol
│ │ │ ├── BooleanEquality.sol
│ │ │ ├── BuiltinSymbolShadow.sol
│ │ │ ├── CacheArrayLength.sol
│ │ │ ├── CallGraphTests.sol
│ │ │ ├── Casting.sol
│ │ │ ├── cloc
│ │ │ │ ├── AnotherHeavilyCommentedContract.sol
│ │ │ │ ├── EmptyContractFile.sol
│ │ │ │ └── HeavilyCommentedContract.sol
│ │ │ ├── CompilerBugStorageSignedIntegerArray.sol
│ │ │ ├── ConstantFuncsAssembly.sol
│ │ │ ├── ConstantsLiterals.sol
│ │ │ ├── ConstFuncChangeState.sol
│ │ │ ├── ContractLocksEther.sol
│ │ │ ├── ContractWithTodo.sol
│ │ │ ├── control_flow
│ │ │ │ └── SimpleProgram.sol
│ │ │ ├── CostlyOperationsInsideLoops.sol
│ │ │ ├── Counter.sol
│ │ │ ├── CrazyPragma.sol
│ │ │ ├── DangerousStrictEquality1.sol
│ │ │ ├── DangerousStrictEquality2.sol
│ │ │ ├── DangerousUnaryOperator.sol
│ │ │ ├── DeadCode.sol
│ │ │ ├── DelegateCallWithoutAddressCheck.sol
│ │ │ ├── DeletionNestedMappingStructureContract.sol
│ │ │ ├── DeprecatedOZFunctions.sol
│ │ │ ├── DivisionBeforeMultiplication.sol
│ │ │ ├── DynamicArrayLengthAssignment.sol
│ │ │ ├── EmitAfterExternalCall.sol
│ │ │ ├── EmptyBlocks.sol
│ │ │ ├── EnumerableSetIteration.sol
│ │ │ ├── eth2
│ │ │ │ └── DepositContract.sol
│ │ │ ├── ExperimentalEncoder.sol
│ │ │ ├── ExternalCalls.sol
│ │ │ ├── FunctionInitializingState.sol
│ │ │ ├── FunctionPointers.sol
│ │ │ ├── FunctionSignatureCollision.sol
│ │ │ ├── HugeConstants.sol
│ │ │ ├── IgnoreEverything.sol
│ │ │ ├── InconsistentUints.sol
│ │ │ ├── IncorrectCaretOperator.sol
│ │ │ ├── IncorrectERC20.sol
│ │ │ ├── IncorrectERC721.sol
│ │ │ ├── IncorrectModifier.sol
│ │ │ ├── IncorrectShift.sol
│ │ │ ├── inheritance
│ │ │ │ ├── ExtendedInheritance.sol
│ │ │ │ ├── IContractInheritance.sol
│ │ │ │ └── InheritanceBase.sol
│ │ │ ├── InternalFunctions.sol
│ │ │ ├── KeccakContract.sol
│ │ │ ├── LocalVariableShadow.sol
│ │ │ ├── MissingInheritance.sol
│ │ │ ├── MisusedBoolean.sol
│ │ │ ├── MsgValueInLoop.sol
│ │ │ ├── MultipleConstructorSchemes.sol
│ │ │ ├── MultiplePlaceholders.sol
│ │ │ ├── nested
│ │ │ │ ├── 1
│ │ │ │ │ └── Nested.sol
│ │ │ │ └── 2
│ │ │ │ └── Nested.sol
│ │ │ ├── nested_mappings
│ │ │ │ ├── LaterVersion.sol
│ │ │ │ └── NestedMappings.sol
│ │ │ ├── OnceModifierExample.sol
│ │ │ ├── OnlyLibrary.sol
│ │ │ ├── OutOfOrderRetryable.sol
│ │ │ ├── parent_chain
│ │ │ │ └── ParentChainContract.sol
│ │ │ ├── PragmaRange.sol
│ │ │ ├── PreDeclaredVarUsage.sol
│ │ │ ├── PublicFunction.sol
│ │ │ ├── PublicVariableReadInExternalContext.sol
│ │ │ ├── RedundantStatements.sol
│ │ │ ├── ReturnBomb.sol
│ │ │ ├── reused_contract_name
│ │ │ │ ├── ContractA.sol
│ │ │ │ └── ContractB.sol
│ │ │ ├── RevertsAndRequriesInLoops.sol
│ │ │ ├── router
│ │ │ │ ├── ExternalCalls.sol
│ │ │ │ ├── FallbackAndReceiveOverrides.sol
│ │ │ │ ├── InternalCalls.sol
│ │ │ │ ├── ModifierCalls.sol
│ │ │ │ └── VarOverridesFunction.sol
│ │ │ ├── RTLO.sol
│ │ │ ├── SendEtherNoChecks.sol
│ │ │ ├── SendEtherNoChecksLibImport.sol
│ │ │ ├── StateChangeAfterExternalCall.sol
│ │ │ ├── StateShadowing.sol
│ │ │ ├── StateVariableCouldBeDeclaredConstant.sol
│ │ │ ├── StateVariableCouldBeDeclaredImmutable.sol
│ │ │ ├── StateVariables.sol
│ │ │ ├── StateVariablesChangesWithoutEvents.sol
│ │ │ ├── StateVariablesManipulation.sol
│ │ │ ├── StorageConditionals.sol
│ │ │ ├── StorageParameters.sol
│ │ │ ├── T11sTranferer.sol
│ │ │ ├── TautologicalCompare.sol
│ │ │ ├── TautologyOrContradiction.sol
│ │ │ ├── TestERC20.sol
│ │ │ ├── TransientKeyword.sol
│ │ │ ├── Trump.sol
│ │ │ ├── TxOriginUsedForAuth.sol
│ │ │ ├── U2.sol
│ │ │ ├── U3.sol
│ │ │ ├── U4.sol
│ │ │ ├── U5.sol
│ │ │ ├── UncheckedCalls.sol
│ │ │ ├── UncheckedReturn.sol
│ │ │ ├── UncheckedSend.sol
│ │ │ ├── UninitializedLocalVariables.sol
│ │ │ ├── UninitializedStateVariable.sol
│ │ │ ├── uniswap
│ │ │ │ ├── UniswapV2Swapper.sol
│ │ │ │ └── UniswapV3Swapper.sol
│ │ │ ├── UnprotectedInitialize.sol
│ │ │ ├── UnsafeERC721Mint.sol
│ │ │ ├── UnusedError.sol
│ │ │ ├── UnusedImport.sol
│ │ │ ├── UnusedStateVariables.sol
│ │ │ ├── UsingSelfdestruct.sol
│ │ │ ├── VoidConstructor.sol
│ │ │ ├── WeakRandomness.sol
│ │ │ ├── WrongOrderOfLayout.sol
│ │ │ ├── YulReturn.sol
│ │ │ └── ZeroAddressCheck.sol
│ │ └── test
│ │ └── Counter.t.sol
│ ├── foundry-nft-f23
│ │ ├── .github
│ │ │ └── workflows
│ │ │ └── test.yml
│ │ ├── .gitignore
│ │ ├── foundry.lock
│ │ ├── foundry.toml
│ │ ├── README.md
│ │ ├── remappings.txt
│ │ └── src
│ │ ├── BasicNft.sol
│ │ ├── F1.sol
│ │ ├── F2.sol
│ │ ├── Initializer.sol
│ │ └── inner-core-modules
│ │ └── ICM.sol
│ ├── foundry-nft-f23-icm
│ │ ├── .github
│ │ │ └── workflows
│ │ │ └── test.yml
│ │ ├── .gitignore
│ │ ├── aderyn.toml
│ │ ├── foundry.toml
│ │ ├── README.md
│ │ ├── remappings.txt
│ │ └── src
│ │ ├── BasicNft.sol
│ │ ├── F1.sol
│ │ ├── F2.sol
│ │ ├── Initializer.sol
│ │ └── inner-core-modules
│ │ └── ICM.sol
│ ├── hardhat-js-playground
│ │ ├── .gitignore
│ │ ├── artifacts
│ │ │ ├── build-info
│ │ │ │ └── cee6fe9a9a2f03f7ff10a27ab2746af6.json
│ │ │ └── contracts
│ │ │ ├── Counter.sol
│ │ │ │ ├── Counter.dbg.json
│ │ │ │ └── Counter.json
│ │ │ ├── ExtendedInheritance.sol
│ │ │ │ ├── ExtendedInheritance.dbg.json
│ │ │ │ └── ExtendedInheritance.json
│ │ │ ├── IContractInheritance.sol
│ │ │ │ ├── IContractInheritance.dbg.json
│ │ │ │ └── IContractInheritance.json
│ │ │ ├── InheritanceBase.sol
│ │ │ │ ├── InheritanceBase.dbg.json
│ │ │ │ └── InheritanceBase.json
│ │ │ ├── KeccakContract.sol
│ │ │ │ ├── KeccakContract.dbg.json
│ │ │ │ └── KeccakContract.json
│ │ │ ├── Lock.sol
│ │ │ │ ├── Lock.dbg.json
│ │ │ │ └── Lock.json
│ │ │ └── StateVariables.sol
│ │ │ ├── StateVariables.dbg.json
│ │ │ └── StateVariables.json
│ │ ├── contracts
│ │ │ ├── Counter.sol
│ │ │ ├── ExtendedInheritance.sol
│ │ │ ├── IContractInheritance.sol
│ │ │ ├── InheritanceBase.sol
│ │ │ ├── KeccakContract.sol
│ │ │ ├── Lock.sol
│ │ │ └── StateVariables.sol
│ │ ├── hardhat.config.js
│ │ ├── package.json
│ │ ├── README.md
│ │ ├── scripts
│ │ │ └── deploy.js
│ │ ├── test
│ │ │ └── Lock.js
│ │ └── yarn.lock
│ ├── no-sol-files
│ │ ├── extra
│ │ │ └── HelloAgain.md
│ │ ├── Hello.txt
│ │ └── Hello.yul
│ └── toml
│ ├── nested_project1
│ │ ├── aderyn.toml
│ │ ├── folder1
│ │ │ └── hardhat.config.ts
│ │ ├── folder2
│ │ │ └── hardhat.config.ts
│ │ └── folder3
│ │ └── file.txt
│ └── nested_project2
│ ├── aderyn.toml
│ ├── folder1
│ │ └── foundry.toml
│ └── folder2
│ └── file1.txt
├── tools
│ └── xtask
│ ├── Cargo.toml
│ └── src
│ ├── blesspr.rs
│ ├── cut_release.rs
│ ├── flags.rs
│ ├── main.rs
│ ├── reportgen.rs
│ └── tomlgen.rs
└── typos.toml
```
# Files
--------------------------------------------------------------------------------
/benchmarks/aderyn/report/both/iteration_times.svg:
--------------------------------------------------------------------------------
```
1 | <svg width="960" height="540" viewBox="0 0 960 540" xmlns="http://www.w3.org/2000/svg">
2 | <text x="480" y="32" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="16.129032258064516" opacity="1" fill="#000000">
3 | aderyn
4 | </text>
5 | <text x="27" y="263" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000" transform="rotate(270, 27, 263)">
6 | Average Iteration Time (ms)
7 | </text>
8 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="87" y1="472" x2="87" y2="53"/>
9 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="171" y1="472" x2="171" y2="53"/>
10 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="256" y1="472" x2="256" y2="53"/>
11 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="340" y1="472" x2="340" y2="53"/>
12 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="425" y1="472" x2="425" y2="53"/>
13 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="509" y1="472" x2="509" y2="53"/>
14 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="594" y1="472" x2="594" y2="53"/>
15 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="678" y1="472" x2="678" y2="53"/>
16 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="763" y1="472" x2="763" y2="53"/>
17 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="847" y1="472" x2="847" y2="53"/>
18 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="932" y1="472" x2="932" y2="53"/>
19 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="87" y1="443" x2="932" y2="443"/>
20 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="87" y1="388" x2="932" y2="388"/>
21 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="87" y1="333" x2="932" y2="333"/>
22 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="87" y1="277" x2="932" y2="277"/>
23 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="87" y1="222" x2="932" y2="222"/>
24 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="87" y1="167" x2="932" y2="167"/>
25 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="87" y1="112" x2="932" y2="112"/>
26 | <line opacity="0.2" stroke="#000000" stroke-width="1" x1="87" y1="56" x2="932" y2="56"/>
27 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="86,53 86,472 "/>
28 | <text x="77" y="443" dy="0.5ex" text-anchor="end" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
29 | 100.0
30 | </text>
31 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="81,443 86,443 "/>
32 | <text x="77" y="388" dy="0.5ex" text-anchor="end" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
33 | 120.0
34 | </text>
35 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="81,388 86,388 "/>
36 | <text x="77" y="333" dy="0.5ex" text-anchor="end" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
37 | 140.0
38 | </text>
39 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="81,333 86,333 "/>
40 | <text x="77" y="277" dy="0.5ex" text-anchor="end" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
41 | 160.0
42 | </text>
43 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="81,277 86,277 "/>
44 | <text x="77" y="222" dy="0.5ex" text-anchor="end" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
45 | 180.0
46 | </text>
47 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="81,222 86,222 "/>
48 | <text x="77" y="167" dy="0.5ex" text-anchor="end" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
49 | 200.0
50 | </text>
51 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="81,167 86,167 "/>
52 | <text x="77" y="112" dy="0.5ex" text-anchor="end" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
53 | 220.0
54 | </text>
55 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="81,112 86,112 "/>
56 | <text x="77" y="56" dy="0.5ex" text-anchor="end" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
57 | 240.0
58 | </text>
59 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="81,56 86,56 "/>
60 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="87,473 932,473 "/>
61 | <text x="87" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
62 | 0
63 | </text>
64 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="87,473 87,478 "/>
65 | <text x="171" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
66 | 10
67 | </text>
68 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="171,473 171,478 "/>
69 | <text x="256" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
70 | 20
71 | </text>
72 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="256,473 256,478 "/>
73 | <text x="340" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
74 | 30
75 | </text>
76 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="340,473 340,478 "/>
77 | <text x="425" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
78 | 40
79 | </text>
80 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="425,473 425,478 "/>
81 | <text x="509" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
82 | 50
83 | </text>
84 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="509,473 509,478 "/>
85 | <text x="594" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
86 | 60
87 | </text>
88 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="594,473 594,478 "/>
89 | <text x="678" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
90 | 70
91 | </text>
92 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="678,473 678,478 "/>
93 | <text x="763" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
94 | 80
95 | </text>
96 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="763,473 763,478 "/>
97 | <text x="847" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
98 | 90
99 | </text>
100 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="847,473 847,478 "/>
101 | <text x="932" y="483" dy="0.76em" text-anchor="middle" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
102 | 100
103 | </text>
104 | <polyline fill="none" opacity="1" stroke="#000000" stroke-width="1" points="932,473 932,478 "/>
105 | <circle cx="95" cy="460" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
106 | <circle cx="103" cy="372" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
107 | <circle cx="112" cy="453" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
108 | <circle cx="120" cy="437" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
109 | <circle cx="129" cy="453" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
110 | <circle cx="137" cy="460" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
111 | <circle cx="146" cy="464" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
112 | <circle cx="154" cy="465" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
113 | <circle cx="163" cy="323" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
114 | <circle cx="171" cy="394" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
115 | <circle cx="179" cy="397" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
116 | <circle cx="188" cy="387" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
117 | <circle cx="196" cy="390" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
118 | <circle cx="205" cy="435" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
119 | <circle cx="213" cy="411" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
120 | <circle cx="222" cy="441" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
121 | <circle cx="230" cy="454" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
122 | <circle cx="239" cy="441" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
123 | <circle cx="247" cy="433" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
124 | <circle cx="256" cy="453" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
125 | <circle cx="264" cy="437" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
126 | <circle cx="272" cy="445" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
127 | <circle cx="281" cy="432" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
128 | <circle cx="289" cy="434" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
129 | <circle cx="298" cy="192" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
130 | <circle cx="306" cy="169" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
131 | <circle cx="315" cy="325" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
132 | <circle cx="323" cy="442" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
133 | <circle cx="332" cy="465" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
134 | <circle cx="340" cy="462" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
135 | <circle cx="348" cy="464" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
136 | <circle cx="357" cy="462" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
137 | <circle cx="365" cy="465" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
138 | <circle cx="374" cy="465" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
139 | <circle cx="382" cy="460" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
140 | <circle cx="391" cy="458" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
141 | <circle cx="399" cy="454" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
142 | <circle cx="408" cy="461" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
143 | <circle cx="416" cy="472" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
144 | <circle cx="425" cy="462" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
145 | <circle cx="433" cy="466" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
146 | <circle cx="441" cy="466" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
147 | <circle cx="450" cy="432" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
148 | <circle cx="458" cy="434" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
149 | <circle cx="467" cy="405" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
150 | <circle cx="475" cy="418" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
151 | <circle cx="484" cy="456" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
152 | <circle cx="492" cy="466" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
153 | <circle cx="501" cy="450" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
154 | <circle cx="509" cy="354" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
155 | <circle cx="517" cy="374" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
156 | <circle cx="526" cy="445" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
157 | <circle cx="534" cy="461" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
158 | <circle cx="543" cy="462" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
159 | <circle cx="551" cy="458" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
160 | <circle cx="560" cy="441" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
161 | <circle cx="568" cy="427" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
162 | <circle cx="577" cy="402" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
163 | <circle cx="585" cy="409" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
164 | <circle cx="594" cy="397" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
165 | <circle cx="602" cy="439" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
166 | <circle cx="610" cy="443" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
167 | <circle cx="619" cy="444" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
168 | <circle cx="627" cy="432" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
169 | <circle cx="636" cy="432" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
170 | <circle cx="644" cy="428" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
171 | <circle cx="653" cy="396" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
172 | <circle cx="661" cy="402" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
173 | <circle cx="670" cy="390" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
174 | <circle cx="678" cy="402" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
175 | <circle cx="686" cy="435" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
176 | <circle cx="695" cy="390" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
177 | <circle cx="703" cy="306" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
178 | <circle cx="712" cy="333" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
179 | <circle cx="720" cy="382" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
180 | <circle cx="729" cy="386" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
181 | <circle cx="737" cy="53" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
182 | <circle cx="746" cy="288" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
183 | <circle cx="754" cy="277" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
184 | <circle cx="763" cy="340" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
185 | <circle cx="771" cy="338" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
186 | <circle cx="779" cy="334" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
187 | <circle cx="788" cy="315" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
188 | <circle cx="796" cy="368" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
189 | <circle cx="805" cy="416" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
190 | <circle cx="813" cy="400" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
191 | <circle cx="822" cy="404" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
192 | <circle cx="830" cy="401" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
193 | <circle cx="839" cy="370" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
194 | <circle cx="847" cy="279" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
195 | <circle cx="855" cy="377" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
196 | <circle cx="864" cy="394" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
197 | <circle cx="872" cy="398" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
198 | <circle cx="881" cy="387" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
199 | <circle cx="889" cy="399" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
200 | <circle cx="898" cy="268" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
201 | <circle cx="906" cy="404" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
202 | <circle cx="915" cy="244" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
203 | <circle cx="923" cy="412" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
204 | <circle cx="932" cy="384" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
205 | <circle cx="95" cy="469" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
206 | <circle cx="103" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
207 | <circle cx="112" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
208 | <circle cx="120" cy="463" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
209 | <circle cx="129" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
210 | <circle cx="137" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
211 | <circle cx="146" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
212 | <circle cx="154" cy="463" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
213 | <circle cx="163" cy="462" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
214 | <circle cx="171" cy="465" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
215 | <circle cx="179" cy="470" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
216 | <circle cx="188" cy="465" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
217 | <circle cx="196" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
218 | <circle cx="205" cy="471" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
219 | <circle cx="213" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
220 | <circle cx="222" cy="461" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
221 | <circle cx="230" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
222 | <circle cx="239" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
223 | <circle cx="247" cy="465" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
224 | <circle cx="256" cy="461" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
225 | <circle cx="264" cy="457" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
226 | <circle cx="272" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
227 | <circle cx="281" cy="471" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
228 | <circle cx="289" cy="470" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
229 | <circle cx="298" cy="462" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
230 | <circle cx="306" cy="370" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
231 | <circle cx="315" cy="435" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
232 | <circle cx="323" cy="458" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
233 | <circle cx="332" cy="465" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
234 | <circle cx="340" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
235 | <circle cx="348" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
236 | <circle cx="357" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
237 | <circle cx="365" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
238 | <circle cx="374" cy="471" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
239 | <circle cx="382" cy="465" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
240 | <circle cx="391" cy="472" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
241 | <circle cx="399" cy="457" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
242 | <circle cx="408" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
243 | <circle cx="416" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
244 | <circle cx="425" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
245 | <circle cx="433" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
246 | <circle cx="441" cy="470" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
247 | <circle cx="450" cy="463" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
248 | <circle cx="458" cy="469" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
249 | <circle cx="467" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
250 | <circle cx="475" cy="472" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
251 | <circle cx="484" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
252 | <circle cx="492" cy="462" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
253 | <circle cx="501" cy="439" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
254 | <circle cx="509" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
255 | <circle cx="517" cy="470" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
256 | <circle cx="526" cy="471" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
257 | <circle cx="534" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
258 | <circle cx="543" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
259 | <circle cx="551" cy="462" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
260 | <circle cx="560" cy="461" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
261 | <circle cx="568" cy="469" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
262 | <circle cx="577" cy="470" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
263 | <circle cx="585" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
264 | <circle cx="594" cy="470" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
265 | <circle cx="602" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
266 | <circle cx="610" cy="470" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
267 | <circle cx="619" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
268 | <circle cx="627" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
269 | <circle cx="636" cy="471" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
270 | <circle cx="644" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
271 | <circle cx="653" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
272 | <circle cx="661" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
273 | <circle cx="670" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
274 | <circle cx="678" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
275 | <circle cx="686" cy="463" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
276 | <circle cx="695" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
277 | <circle cx="703" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
278 | <circle cx="712" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
279 | <circle cx="720" cy="463" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
280 | <circle cx="729" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
281 | <circle cx="737" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
282 | <circle cx="746" cy="465" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
283 | <circle cx="754" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
284 | <circle cx="763" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
285 | <circle cx="771" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
286 | <circle cx="779" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
287 | <circle cx="788" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
288 | <circle cx="796" cy="465" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
289 | <circle cx="805" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
290 | <circle cx="813" cy="353" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
291 | <circle cx="822" cy="462" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
292 | <circle cx="830" cy="462" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
293 | <circle cx="839" cy="465" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
294 | <circle cx="847" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
295 | <circle cx="855" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
296 | <circle cx="864" cy="468" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
297 | <circle cx="872" cy="462" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
298 | <circle cx="881" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
299 | <circle cx="889" cy="465" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
300 | <circle cx="898" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
301 | <circle cx="906" cy="464" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
302 | <circle cx="915" cy="466" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
303 | <circle cx="923" cy="467" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
304 | <circle cx="932" cy="463" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
305 | <text x="132" y="68" dy="0.76em" text-anchor="start" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
306 | Current
307 | </text>
308 | <text x="132" y="83" dy="0.76em" text-anchor="start" font-family="sans-serif" font-size="9.67741935483871" opacity="1" fill="#000000">
309 | Base
310 | </text>
311 | <circle cx="112" cy="73" r="3" opacity="1" fill="#1F78B4" stroke="none" stroke-width="1"/>
312 | <circle cx="112" cy="88" r="3" opacity="1" fill="#E31A1C" stroke="none" stroke-width="1"/>
313 | </svg>
314 |
```
--------------------------------------------------------------------------------
/aderyn_core/src/context/browser/storage_vars.rs:
--------------------------------------------------------------------------------
```rust
1 | use crate::{
2 | ast::*,
3 | context::workspace::WorkspaceContext,
4 | visitor::ast_visitor::{ASTConstVisitor, Node},
5 | };
6 | use eyre::*;
7 | use std::{
8 | collections::{BTreeMap, BTreeSet},
9 | fmt::Debug,
10 | iter::zip,
11 | ops::Add,
12 | };
13 |
14 | /// Given an AST Block, it tries to detect any state variable inside it that may have been
15 | /// manipulated. Now it's important to know that manipulations can occur either directly by
16 | /// assigning to a state variable or, it may occur by assigning to a storage pointer that points to
17 | /// some state variable. This light weight state variable manipulation finder captures both of the
18 | /// above kinds of assignments. However, it's not smart enough to use a data dependency graph to
19 | /// determine the exact state variables these storage pointers would be pointing to, in the context
20 | /// of the block-flow.
21 | ///
22 | /// NOTE - Assignment is not the only avenue for manipulating state variables, but also operations
23 | /// like `push()` and `pop()` on arrays, `M[i] = x` on mappings, `delete X` imply the same.
24 | ///
25 | /// Here, the term manipulation covers all kinds of changes discussed above.
26 | ///
27 | /// IMPORTANT: DO NOT MAKE THESE MEMBERS PUBLIC. Use the public methods implemented on this
28 | /// structure only.
29 | pub struct ApproximateStorageChangeFinder<'a> {
30 | directly_manipulated_state_variables: BTreeSet<NodeID>,
31 | manipulated_storage_pointers: BTreeSet<NodeID>,
32 | /// Key => State Variable ID, Value => Storage Pointer ID (Heuristics based, this map is NOT
33 | /// exhaustive) It leaves out a lot of links especially in cases where storage pointers are
34 | /// passed to and fro internal functions. But on average, for most cases the way code is
35 | /// generally written, this should contain a decent chunk of links to lookup.
36 | state_variables_to_storage_pointers: BTreeMap<NodeID, BTreeSet<NodeID>>,
37 | context: &'a WorkspaceContext,
38 | }
39 |
40 | /// This trait implementation will be useful when we run it through our callgraph and try to
41 | /// aggregate state variable changes.
42 | impl<'a> Add<ApproximateStorageChangeFinder<'_>> for ApproximateStorageChangeFinder<'a> {
43 | type Output = ApproximateStorageChangeFinder<'a>;
44 |
45 | fn add(mut self, rhs: ApproximateStorageChangeFinder) -> Self::Output {
46 | self.directly_manipulated_state_variables
47 | .extend(rhs.directly_manipulated_state_variables.iter());
48 | self.manipulated_storage_pointers.extend(rhs.manipulated_storage_pointers.iter());
49 | // For state_variables_to_storage_pointers, we have to "add" the storage point entry vectors
50 | for (state_var_id, storage_pointer_ids) in &rhs.state_variables_to_storage_pointers {
51 | match self.state_variables_to_storage_pointers.entry(*state_var_id) {
52 | std::collections::btree_map::Entry::Vacant(v) => {
53 | v.insert(BTreeSet::from_iter(storage_pointer_ids.iter().copied()));
54 | }
55 | std::collections::btree_map::Entry::Occupied(mut o) => {
56 | (*o.get_mut()).extend(storage_pointer_ids);
57 | }
58 | };
59 | }
60 | self
61 | }
62 | }
63 |
64 | impl Debug for ApproximateStorageChangeFinder<'_> {
65 | // Do not print context. Hence, debug is custom derived for this struct
66 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 | writeln!(f, "Manipulated directly: {:?}", self.directly_manipulated_state_variables)?;
68 |
69 | if !self.directly_manipulated_state_variables.is_empty() {
70 | writeln!(f, "↓↓")?;
71 | for id in &self.directly_manipulated_state_variables {
72 | if let Some(node) = self.context.nodes.get(id) {
73 | let loc_info = self.context.get_node_sort_key(node);
74 | writeln!(f, "Line {:?}", (loc_info.1, loc_info.2))?;
75 | } else {
76 | writeln!(f, "<unknown_node_id_{}>\n", id)?;
77 | }
78 | }
79 | writeln!(f)?;
80 | }
81 |
82 | writeln!(
83 | f,
84 | "Manipulated through storage pointers: {:?}",
85 | self.manipulated_storage_pointers
86 | )?;
87 |
88 | if !self.manipulated_storage_pointers.is_empty() {
89 | writeln!(f, "↓↓")?;
90 | for id in &self.manipulated_storage_pointers {
91 | if let Some(node) = self.context.nodes.get(id) {
92 | let loc_info = self.context.get_node_sort_key(node);
93 | writeln!(f, "Line {:?}", (loc_info.1, loc_info.2))?;
94 | } else {
95 | writeln!(f, "<unknown_node_id_{}>", id)?;
96 | }
97 | }
98 | writeln!(f)?;
99 | }
100 |
101 | writeln!(f, "Links heuristics: {:?}", self.state_variables_to_storage_pointers)?;
102 |
103 | if !self.state_variables_to_storage_pointers.is_empty() {
104 | writeln!(f, "↓↓")?;
105 | for (state_variable_id, storage_pointer_references) in
106 | &self.state_variables_to_storage_pointers
107 | {
108 | if let Some(node) = self.context.nodes.get(state_variable_id) {
109 | let loc_info = self.context.get_node_sort_key(node);
110 | writeln!(f, "Links to {:?}", (loc_info.1, loc_info.2))?;
111 | for node_id in storage_pointer_references {
112 | if let Some(node) = self.context.nodes.get(node_id) {
113 | let loc_info = self.context.get_node_sort_key(node);
114 | writeln!(f, "\t <> {:?}", (loc_info.1, loc_info.2))?;
115 | }
116 | }
117 | } else {
118 | writeln!(f, "<unknown_node_id_{}>", state_variable_id)?;
119 | }
120 | }
121 | writeln!(f)?;
122 | }
123 |
124 | std::fmt::Result::Ok(())
125 | }
126 | }
127 |
128 | /// Interface to be used by other modules defined here.
129 | impl<'a> ApproximateStorageChangeFinder<'a> {
130 | /// Initialize
131 | pub fn from<T: Node + ?Sized>(context: &'a WorkspaceContext, node: &T) -> Self {
132 | let mut extractor = ApproximateStorageChangeFinder {
133 | directly_manipulated_state_variables: BTreeSet::new(),
134 | manipulated_storage_pointers: BTreeSet::new(),
135 | state_variables_to_storage_pointers: BTreeMap::new(),
136 | context,
137 | };
138 | node.accept(&mut extractor).unwrap_or_default();
139 | extractor
140 | }
141 |
142 | pub fn state_variables_have_been_manipulated(&self) -> bool {
143 | !self.directly_manipulated_state_variables.is_empty()
144 | || !self.manipulated_storage_pointers.is_empty()
145 | }
146 |
147 | pub fn no_state_variable_has_been_manipulated(&self) -> bool {
148 | self.directly_manipulated_state_variables.is_empty()
149 | && self.manipulated_storage_pointers.is_empty()
150 | }
151 |
152 | pub fn fetch_non_exhaustive_manipulated_state_variables(&self) -> Vec<&VariableDeclaration> {
153 | let mut manipulated_state_vars: BTreeSet<NodeID> = BTreeSet::new();
154 | manipulated_state_vars.extend(self.directly_manipulated_state_variables.iter());
155 | for (state_variable_id, storage_pointers) in self.state_variables_to_storage_pointers.iter()
156 | {
157 | if storage_pointers.iter().any(|ptr| self.manipulated_storage_pointers.contains(ptr)) {
158 | manipulated_state_vars.insert(*state_variable_id);
159 | }
160 | }
161 | manipulated_state_vars
162 | .into_iter()
163 | .flat_map(|v| self.context.nodes.get(&v))
164 | .flat_map(|n| {
165 | if let ASTNode::VariableDeclaration(variable_declaration) = n {
166 | assert!(variable_declaration.state_variable);
167 | return Some(variable_declaration);
168 | }
169 | None
170 | })
171 | .collect()
172 | }
173 |
174 | pub fn state_variable_has_been_manipulated(&self, var: &VariableDeclaration) -> Option<bool> {
175 | if self.directly_manipulated_state_variables.contains(&var.id) {
176 | return Some(true);
177 | }
178 | if self.manipulated_storage_pointers.is_empty() {
179 | return Some(false);
180 | }
181 | // Now use our heuristics
182 | if self.state_variables_to_storage_pointers.get(&var.id).is_some_and(|entry| {
183 | entry.iter().any(|e| self.manipulated_storage_pointers.contains(e))
184 | }) {
185 | return Some(true);
186 | }
187 |
188 | // At this point, we don't know if any of the storage pointers refer to [`var`], so we
189 | // cannot say for sure, if it has been manipulated or not.
190 | None
191 | }
192 |
193 | pub fn state_variable_has_not_been_manipulated(
194 | &self,
195 | var: &VariableDeclaration,
196 | ) -> Option<bool> {
197 | if self.directly_manipulated_state_variables.contains(&var.id) {
198 | return Some(false);
199 | }
200 | if self.manipulated_storage_pointers.is_empty() {
201 | return Some(true);
202 | }
203 | // Now use our heuristics
204 | if self.state_variables_to_storage_pointers.get(&var.id).is_some_and(|entry| {
205 | entry.iter().any(|e| self.manipulated_storage_pointers.contains(e))
206 | }) {
207 | return Some(false);
208 | }
209 |
210 | // At this point, we don't know if any of the storage pointers refer to [`var`], so we
211 | // cannot say for sure, if it has been manipulated or not.
212 | None
213 | }
214 | }
215 |
216 | impl ASTConstVisitor for ApproximateStorageChangeFinder<'_> {
217 | fn visit_unary_operation(&mut self, node: &UnaryOperation) -> Result<bool> {
218 | // WRITE HEURISTICS
219 | // Catch unary operations that manipulate variables
220 | if node.operator == "delete" || node.operator == "++" || node.operator == "--" {
221 | for id in find_base(node.sub_expression.as_ref()).0 {
222 | match is_storage_variable_or_storage_pointer(self.context, id) {
223 | Some(AssigneeType::StateVariable) => {
224 | self.directly_manipulated_state_variables.insert(id);
225 | }
226 | Some(AssigneeType::StorageLocationVariable) => {
227 | self.manipulated_storage_pointers.insert(id);
228 | }
229 | None => {}
230 | };
231 | }
232 | }
233 |
234 | Ok(true)
235 | }
236 |
237 | fn visit_member_access(&mut self, member: &MemberAccess) -> Result<bool> {
238 | if !member.expression.type_descriptions().is_some_and(|type_desc| {
239 | type_desc.type_string.as_ref().is_some_and(|type_string| {
240 | type_string.ends_with("[] storage ref")
241 | || type_string.ends_with("[] storage pointer")
242 | })
243 | }) {
244 | return Ok(true);
245 | }
246 |
247 | let (base_variable_ids, _) = find_base(member.expression.as_ref());
248 | // assert!(base_variable_ids.len() == 1);
249 |
250 | // WRITE HEURISTICS
251 | if member.member_name == "push" || member.member_name == "pop" {
252 | for id in base_variable_ids.iter() {
253 | match is_storage_variable_or_storage_pointer(self.context, *id) {
254 | Some(AssigneeType::StateVariable) => {
255 | self.directly_manipulated_state_variables.insert(*id);
256 | }
257 | Some(AssigneeType::StorageLocationVariable) => {
258 | self.manipulated_storage_pointers.insert(*id);
259 | }
260 | None => {}
261 | };
262 | }
263 | }
264 |
265 | Ok(true)
266 | }
267 |
268 | fn visit_assignment(&mut self, assignment: &Assignment) -> Result<bool> {
269 | let (base_variable_lhs_ids, type_strings) = find_base(assignment.left_hand_side.as_ref());
270 | let (base_variable_rhs_ids, _) = find_base(assignment.right_hand_side.as_ref());
271 |
272 | for (id, type_string) in zip(base_variable_lhs_ids.iter(), type_strings.iter()) {
273 | // When something is assigned to an expression of type "storage pointer", no state
274 | // variable's value changes. The only value changed is the thing which the
275 | // storage pointer points to. The value of a storage variable changes if the
276 | // expression's type string contains "storage ref" in case of structs, arrays, etc
277 |
278 | if type_string.ends_with("storage pointer") {
279 | continue;
280 | }
281 |
282 | match is_storage_variable_or_storage_pointer(self.context, *id) {
283 | Some(AssigneeType::StateVariable) => {
284 | self.directly_manipulated_state_variables.insert(*id);
285 | }
286 | Some(AssigneeType::StorageLocationVariable) => {
287 | self.manipulated_storage_pointers.insert(*id);
288 | }
289 | None => {}
290 | };
291 | }
292 |
293 | // Now, on a separate note, let's look for a heuristic to link up state variables with
294 | // storage pointers. But here, we only handle the cases when there are equal number
295 | // of elements on either side of `=` . This allows us to assume 1:1 relationship.
296 | if base_variable_lhs_ids.len() == base_variable_rhs_ids.len() {
297 | for (lhs_id, rhs_id) in zip(base_variable_lhs_ids, base_variable_rhs_ids) {
298 | if let (
299 | Some(AssigneeType::StorageLocationVariable),
300 | Some(AssigneeType::StateVariable),
301 | ) = (
302 | is_storage_variable_or_storage_pointer(self.context, lhs_id),
303 | is_storage_variable_or_storage_pointer(self.context, rhs_id),
304 | ) {
305 | match self.state_variables_to_storage_pointers.entry(rhs_id) {
306 | std::collections::btree_map::Entry::Vacant(v) => {
307 | v.insert(BTreeSet::from_iter([lhs_id]));
308 | }
309 | std::collections::btree_map::Entry::Occupied(mut o) => {
310 | (*o.get_mut()).insert(lhs_id);
311 | }
312 | };
313 | }
314 | }
315 | }
316 |
317 | // READ HEURISTICS
318 | // Pretty much the same logic as described in `visit_variable_declaration_statement`
319 | //
320 |
321 | // let (left_node_ids, _) = find_base(assignment.left_hand_side.as_ref());
322 | // let right_node_ids = flatten_expression(assignment.right_hand_side.as_ref());
323 |
324 | // See if it's a 1:1 relationship. Only then, proceed. Later, we can think of heuristics to
325 | // handle x:y (but likely we will have to rely on a dependency graph for that. Case:
326 | // `(x, y) = func()` is out of scope for this).
327 | //
328 | // When it comes to tracking WRITEs, it doesn't matter what's on RHS of `=`
329 | // When it comes to tracking READs, it does! If the LHS type is storage then you are simply
330 | // carrying a reference at compile time, you are not actually reading. Whereas, if
331 | // the LHS is memory, you are performing "sload"! But again, this logic changes
332 | // based on type of value in RHS. If it's a function call you should look at
333 | // return values and nature of the corresponding variable where that value will be stored.
334 | // Likewise, different for different nodes albeit identifier one is probably the
335 | // most straightforward if left_node_ids.len() == right_node_ids.len() {}
336 |
337 | Ok(true)
338 | }
339 |
340 | // For heurstics: Try to link up as much storage pointers and state variables as possible
341 | fn visit_variable_declaration_statement(
342 | &mut self,
343 | node: &VariableDeclarationStatement,
344 | ) -> Result<bool> {
345 | if let Some(initial_value) = node.initial_value.as_ref() {
346 | let corresponding_variable_declaration_ids = node
347 | .declarations
348 | .iter()
349 | .map(|v| {
350 | if let Some(variable_declaration) = v {
351 | variable_declaration.id
352 | } else {
353 | i64::MIN
354 | }
355 | })
356 | .collect::<Vec<_>>();
357 | let initial_value_node_ids = flatten_expression(initial_value); // For READ heuristics
358 | let (initial_value_bases, _) = find_base(initial_value); // For LINK heuristics
359 |
360 | // Let's first support 1:1 relationships only
361 | if corresponding_variable_declaration_ids.len() == initial_value_node_ids.len() {
362 | let common_len = corresponding_variable_declaration_ids.len();
363 |
364 | // This for loop takes care of recording instances in VDS (Var Decl Stmnt) where
365 | // there is a read from the storage.
366 | //
367 | // READ HEURISTICS
368 | //
369 | // TODO: Write tests for these
370 | // Then creates `passes_read_check()` before matching the var id on extracting
371 | // reference declarations Then replicate the logic for assignments
372 | // use lvaluerequested = false and islvalue = true to check if it's being read
373 | // in case of visiting indexaccess, memberaccess, etc (expr_node! variants)
374 | // So that it can detect stuff outside of just assignments. Example -
375 | // functionCall(a.b) where a is state var (Technically you are
376 | // reading a.b's value to make that function call)
377 | //
378 | // for i in 0..common_len {
379 | // let variable_declaration_id = corresponding_variable_declaration_ids[i];
380 | // let corresponding_initial_value_id = initial_value_node_ids[i];
381 |
382 | // if is_storage_variable_or_storage_pointer(
383 | // &self.context,
384 | // variable_declaration_id,
385 | // )
386 | // .is_some()
387 | // {
388 | // // If we are not assigning something to a storage pointer or a storage
389 | // reference, that means // we're storing it in memory.
390 | // Therefore, we can consider that the corresponding initialValue
391 | // // is being "read". Otherwise we are just creating pointers, not
392 | // "sload"ing. continue;
393 | // }
394 |
395 | // if let Some(node) = self.context.nodes.get(&corresponding_initial_value_id) {
396 | // // In case of internal function call, it's complex to analyze
397 | // if node.node_type() != NodeType::FunctionCall || it is{
398 | // let referenced_declarations =
399 | // ExtractReferencedDeclarations::from(node).extracted;
400 |
401 | // for variable_id in referenced_declarations {
402 | // match is_storage_variable_or_storage_pointer(
403 | // self.context,
404 | // variable_id,
405 | // ) {
406 | // // Assumption: At this point in code we know that it could be
407 | // a storage pointer/variable that represents //
408 | // uint, bool, array element, etc. so it's technically being read.
409 | // Some(AssigneeType::StateVariable) => {
410 | // self.directly_read_state_variables.insert(variable_id);
411 | // }
412 | // Some(AssigneeType::StorageLocationVariable) => {
413 | // self.read_storage_pointers.insert(variable_id);
414 | // }
415 | // None => {}
416 | // }
417 | // }
418 | // }
419 | // }
420 | // }
421 |
422 | assert!(initial_value_bases.len() == common_len);
423 |
424 | // LINK heuristics
425 | for i in 0..common_len {
426 | let variable_declaration_id = corresponding_variable_declaration_ids[i];
427 | let corresponding_initial_value_base_id = initial_value_bases[i];
428 |
429 | if let (
430 | Some(AssigneeType::StorageLocationVariable),
431 | Some(AssigneeType::StateVariable),
432 | ) = (
433 | is_storage_variable_or_storage_pointer(
434 | self.context,
435 | variable_declaration_id,
436 | ),
437 | is_storage_variable_or_storage_pointer(
438 | self.context,
439 | corresponding_initial_value_base_id,
440 | ),
441 | ) {
442 | match self
443 | .state_variables_to_storage_pointers
444 | .entry(corresponding_initial_value_base_id)
445 | {
446 | std::collections::btree_map::Entry::Vacant(v) => {
447 | v.insert(BTreeSet::from_iter([variable_declaration_id]));
448 | }
449 | std::collections::btree_map::Entry::Occupied(mut o) => {
450 | (*o.get_mut()).insert(variable_declaration_id);
451 | }
452 | };
453 | }
454 | }
455 | }
456 | }
457 |
458 | Ok(true)
459 | }
460 | }
461 |
462 | fn flatten_expression(expr: &Expression) -> Vec<NodeID> {
463 | let mut node_ids = vec![];
464 | match expr {
465 | Expression::TupleExpression(TupleExpression { components, .. }) => {
466 | for component in components.iter().flatten() {
467 | let component_node_ids = flatten_expression(component);
468 | node_ids.extend(component_node_ids);
469 | }
470 | }
471 | _ => {
472 | node_ids.push(expr.get_node_id().unwrap_or(i64::MIN));
473 | }
474 | }
475 | node_ids
476 | }
477 |
478 | fn find_base(expr: &Expression) -> (Vec<NodeID>, Vec<String>) {
479 | let mut node_ids = vec![];
480 | let mut type_strings = vec![];
481 | match expr {
482 | Expression::Identifier(Identifier {
483 | referenced_declaration: Some(id),
484 | type_descriptions: TypeDescriptions { type_string: Some(type_string), .. },
485 | ..
486 | }) => {
487 | node_ids.push(*id);
488 | type_strings.push(type_string.clone());
489 | }
490 | // Handle mappings assignment
491 | Expression::IndexAccess(IndexAccess {
492 | base_expression,
493 | type_descriptions: TypeDescriptions { type_string: Some(type_string), .. },
494 | ..
495 | }) => {
496 | node_ids.extend(find_base(base_expression.as_ref()).0);
497 | type_strings.push(type_string.clone());
498 | }
499 | // Handle struct member assignment
500 | Expression::MemberAccess(MemberAccess {
501 | expression,
502 | type_descriptions: TypeDescriptions { type_string: Some(type_string), .. },
503 | ..
504 | }) => {
505 | node_ids.extend(find_base(expression.as_ref()).0);
506 | type_strings.push(type_string.clone());
507 | }
508 | // Handle tuple form lhs while assigning
509 | Expression::TupleExpression(TupleExpression { components, .. }) => {
510 | for component in components.iter() {
511 | if let Some(component) = component {
512 | let (component_node_ids, component_type_strings) = find_base(component);
513 | node_ids.extend(component_node_ids);
514 | type_strings.extend(component_type_strings);
515 | } else {
516 | node_ids.push(i64::MIN);
517 | type_strings.push(String::from("irrelevant"));
518 | }
519 | }
520 | }
521 | // Handle assignment with values like ++i, --j, i++, etc
522 | Expression::UnaryOperation(UnaryOperation {
523 | sub_expression,
524 | type_descriptions: TypeDescriptions { type_string: Some(type_string), .. },
525 | ..
526 | }) => {
527 | node_ids.extend(find_base(sub_expression.as_ref()).0);
528 | type_strings.push(type_string.clone());
529 | }
530 | _ => {
531 | node_ids.push(i64::MIN);
532 | type_strings.push(String::from("irrelevant"));
533 | }
534 | };
535 | assert_eq!(node_ids.len(), type_strings.len());
536 | (node_ids, type_strings)
537 | }
538 |
539 | #[derive(PartialEq)]
540 | enum AssigneeType {
541 | StateVariable,
542 | StorageLocationVariable,
543 | }
544 |
545 | fn is_storage_variable_or_storage_pointer(
546 | context: &WorkspaceContext,
547 | node_id: NodeID,
548 | ) -> Option<AssigneeType> {
549 | let node = context.nodes.get(&node_id)?;
550 | if let ASTNode::VariableDeclaration(variable) = node {
551 | if variable.storage_location == StorageLocation::Transient {
552 | return None;
553 | }
554 | // Assumption
555 | // variable.state_variable is true when it's an actual state variable
556 | // variable.storage_location is StorageLocation::Storage when it's a storage reference
557 | // pointer
558 | if variable.state_variable {
559 | return Some(AssigneeType::StateVariable);
560 | } else if variable.storage_location == StorageLocation::Storage {
561 | return Some(AssigneeType::StorageLocationVariable);
562 | }
563 | }
564 | None
565 | }
566 |
567 | #[cfg(test)]
568 | mod approximate_storage_change_finder_tests {
569 | use crate::detect::test_utils::load_solidity_source_unit;
570 |
571 | use super::ApproximateStorageChangeFinder;
572 |
573 | #[test]
574 |
575 | fn has_variable_declarations() {
576 | let context = load_solidity_source_unit(
577 | "../tests/contract-playground/src/StateVariablesManipulation.sol",
578 | );
579 |
580 | assert!(!context.variable_declarations().is_empty());
581 | }
582 |
583 | #[test]
584 |
585 | fn test_no_state_variable_manipulations_found() {
586 | let context = load_solidity_source_unit(
587 | "../tests/contract-playground/src/StateVariablesManipulation.sol",
588 | );
589 |
590 | let contract = context.find_contract_by_name("NoStateVarManipulationExample");
591 | let func = contract.find_function_by_name("dontManipulateStateVar");
592 |
593 | let finder = ApproximateStorageChangeFinder::from(&context, func);
594 | let no_changes_found = !finder.state_variables_have_been_manipulated();
595 | println!("NoStateVarManipulationExample::dontManipulateStateVar()\n{:?}", finder);
596 | println!("{:?}", finder);
597 | assert!(no_changes_found);
598 | }
599 |
600 | #[test]
601 |
602 | fn test_simple_state_variable_manipulations_found() {
603 | let context = load_solidity_source_unit(
604 | "../tests/contract-playground/src/StateVariablesManipulation.sol",
605 | );
606 |
607 | let contract = context.find_contract_by_name("SimpleStateVarManipulationExample");
608 | let func = contract.find_function_by_name("manipulateStateVarDirectly");
609 | let func2 = contract.find_function_by_name("readSimpleStateVars");
610 |
611 | let finder = ApproximateStorageChangeFinder::from(&context, func);
612 | let changes_found = finder.state_variables_have_been_manipulated();
613 | println!("SimpleStateVarManipulationExample::manipulateStateVarDirectly()\n{:?}", finder);
614 | assert!(changes_found);
615 | assert_eq!(finder.directly_manipulated_state_variables.len(), 5);
616 | assert!(finder.manipulated_storage_pointers.is_empty());
617 |
618 | let finder = ApproximateStorageChangeFinder::from(&context, func2);
619 | let changes_found = finder.state_variables_have_been_manipulated();
620 | println!("SimpleStateVarManipulationExample::readSimpleStateVars()\n{:?}", finder);
621 | assert!(!changes_found);
622 | assert!(finder.directly_manipulated_state_variables.is_empty());
623 | assert!(finder.manipulated_storage_pointers.is_empty());
624 | }
625 |
626 | #[test]
627 |
628 | fn test_fixed_size_array_assignments() {
629 | let context = load_solidity_source_unit(
630 | "../tests/contract-playground/src/StateVariablesManipulation.sol",
631 | );
632 |
633 | let contract = context.find_contract_by_name("FixedSizeArraysAssignmentExample");
634 |
635 | let func1 = contract.find_function_by_name("manipulateDirectly");
636 | let func2 = contract.find_function_by_name("manipulateViaIndexAccess");
637 |
638 | // Test manipulateDirectly() function
639 |
640 | let finder = ApproximateStorageChangeFinder::from(&context, func1);
641 | println!("FixedSizeArraysAssignmentExample::manipulateDirectly()\n{:?}", finder);
642 |
643 | let changes_found = finder.state_variables_have_been_manipulated();
644 | assert!(changes_found);
645 | assert_eq!(finder.directly_manipulated_state_variables.len(), 1);
646 | assert!(finder.manipulated_storage_pointers.is_empty());
647 |
648 | // Test manipulateViaIndexAccess() function
649 |
650 | let finder = ApproximateStorageChangeFinder::from(&context, func2);
651 | println!("FixedSizeArraysAssignmentExample::manipulateViaIndexAccess()\n{:?}", finder);
652 |
653 | let changes_found2 = finder.state_variables_have_been_manipulated();
654 | assert!(changes_found2);
655 | assert_eq!(finder.directly_manipulated_state_variables.len(), 2);
656 | assert!(finder.manipulated_storage_pointers.is_empty());
657 | }
658 |
659 | #[test]
660 |
661 | fn test_struct_plus_fixed_array_assignment_example() {
662 | let context = load_solidity_source_unit(
663 | "../tests/contract-playground/src/StateVariablesManipulation.sol",
664 | );
665 |
666 | let contract = context.find_contract_by_name("StructPlusFixedArrayAssignmentExample");
667 |
668 | let func = contract.find_function_by_name("manipulateStateVariables");
669 | let func2 = contract.find_function_by_name("manipulateStateVariables2");
670 | let func3 = contract.find_function_by_name("manipulateStateVariables3");
671 | let func4 = contract.find_function_by_name("manipulateStateVariables4");
672 | let func5 = contract.find_function_by_name("manipulateStateVariables5");
673 | let func6 = contract.find_function_by_name("manipulateStateVariables6");
674 | let func7 = contract.find_function_by_name("manipulateStateVariables7");
675 | let func8 = contract.find_function_by_name("manipulateStateVariables8");
676 | let func_helper = contract.find_function_by_name("manipulateHelper");
677 |
678 | // Test manipulateStateVariables
679 | let finder = ApproximateStorageChangeFinder::from(&context, func);
680 | println!("StructPlusFixedArrayAssignmentExample::manipulateStateVariables()\n{:?}", finder);
681 | let changes_found = finder.state_variables_have_been_manipulated();
682 | assert!(changes_found);
683 | assert_eq!(finder.directly_manipulated_state_variables.len(), 3);
684 | assert!(finder.manipulated_storage_pointers.is_empty());
685 |
686 | // Test manipulateStateVariables2
687 | let finder = ApproximateStorageChangeFinder::from(&context, func2);
688 | println!(
689 | "StructPlusFixedArrayAssignmentExample::manipulateStateVariables2()\n{:?}",
690 | finder
691 | );
692 | let changes_found = finder.state_variables_have_been_manipulated();
693 | assert!(changes_found);
694 | assert_eq!(finder.manipulated_storage_pointers.len(), 1);
695 | assert_eq!(
696 | finder
697 | .state_variables_to_storage_pointers
698 | .get(&contract.find_state_variable_node_id_by_name("person3"))
699 | .unwrap()
700 | .len(),
701 | 1
702 | );
703 | assert_eq!(
704 | finder
705 | .state_variables_to_storage_pointers
706 | .get(&contract.find_state_variable_node_id_by_name("persons"))
707 | .unwrap()
708 | .len(),
709 | 1
710 | );
711 | assert!(finder.directly_manipulated_state_variables.is_empty());
712 |
713 | // Test manipulateStateVariables3
714 | let finder = ApproximateStorageChangeFinder::from(&context, func3);
715 | println!(
716 | "StructPlusFixedArrayAssignmentExample::manipulateStateVariables3()\n{:?}",
717 | finder
718 | );
719 | let no_changes_found = !finder.state_variables_have_been_manipulated();
720 | assert!(no_changes_found);
721 | assert!(finder.manipulated_storage_pointers.is_empty());
722 | assert!(finder.directly_manipulated_state_variables.is_empty());
723 | assert_eq!(finder.state_variables_to_storage_pointers.len(), 1); // person3 links to ptr_person3
724 | assert_eq!(
725 | finder
726 | .state_variables_to_storage_pointers
727 | .get(&contract.find_state_variable_node_id_by_name("person3"))
728 | .unwrap()
729 | .len(),
730 | 1
731 | );
732 |
733 | // Test manipulateStateVariables4
734 | let finder = ApproximateStorageChangeFinder::from(&context, func4);
735 | println!(
736 | "StructPlusFixedArrayAssignmentExample::manipulateStateVariables4()\n{:?}",
737 | finder
738 | );
739 | let no_changes_found = !finder.state_variables_have_been_manipulated();
740 | assert!(no_changes_found);
741 | assert!(finder.manipulated_storage_pointers.is_empty());
742 | assert!(finder.directly_manipulated_state_variables.is_empty());
743 |
744 | // Test manipulateStateVariables5
745 | let finder = ApproximateStorageChangeFinder::from(&context, func5);
746 | println!(
747 | "StructPlusFixedArrayAssignmentExample::manipulateStateVariables5()\n{:?}",
748 | finder
749 | );
750 | let no_changes_found = !finder.state_variables_have_been_manipulated();
751 | assert!(no_changes_found);
752 | assert!(finder.manipulated_storage_pointers.is_empty());
753 | assert!(finder.directly_manipulated_state_variables.is_empty());
754 | assert_eq!(finder.state_variables_to_storage_pointers.len(), 1);
755 | assert_eq!(
756 | finder
757 | .state_variables_to_storage_pointers
758 | .get(&contract.find_state_variable_node_id_by_name("person3"))
759 | .unwrap()
760 | .len(),
761 | 1
762 | );
763 |
764 | // Test funcHelper
765 | let finder = ApproximateStorageChangeFinder::from(&context, func_helper);
766 | println!("StructPlusFixedArrayAssignmentExample::manipulateHelper()\n{:?}", finder);
767 | let changes_found = finder.state_variables_have_been_manipulated();
768 | assert!(changes_found);
769 | assert_eq!(finder.manipulated_storage_pointers.len(), 2);
770 | assert!(finder.directly_manipulated_state_variables.is_empty());
771 | assert_eq!(
772 | finder
773 | .state_variables_to_storage_pointers
774 | .get(&contract.find_state_variable_node_id_by_name("person3"))
775 | .unwrap()
776 | .len(),
777 | 1
778 | );
779 |
780 | // Test manipulateStateVariables6
781 | let finder = ApproximateStorageChangeFinder::from(&context, func6);
782 | println!(
783 | "StructPlusFixedArrayAssignmentExample::manipulateStateVariables6()\n{:?}",
784 | finder
785 | );
786 | let changes_found = finder.state_variables_have_been_manipulated();
787 | assert!(changes_found);
788 | assert_eq!(finder.manipulated_storage_pointers.len(), 2);
789 | assert!(finder.directly_manipulated_state_variables.is_empty());
790 | assert_eq!(
791 | finder
792 | .state_variables_to_storage_pointers
793 | .get(&contract.find_state_variable_node_id_by_name("person3"))
794 | .unwrap()
795 | .len(),
796 | 4
797 | );
798 |
799 | // Test manipulateStateVariables7
800 | let finder = ApproximateStorageChangeFinder::from(&context, func7);
801 | println!(
802 | "StructPlusFixedArrayAssignmentExample::manipulateStateVariables7()\n{:?}",
803 | finder
804 | );
805 | let changes_found = finder.state_variables_have_been_manipulated();
806 | assert!(changes_found);
807 | assert!(finder.manipulated_storage_pointers.is_empty());
808 | assert_eq!(finder.directly_manipulated_state_variables.len(), 3);
809 |
810 | // Test manipulateStateVariables8
811 | let finder = ApproximateStorageChangeFinder::from(&context, func8);
812 | println!(
813 | "StructPlusFixedArrayAssignmentExample::manipulateStateVariables8()\n{:?}",
814 | finder
815 | );
816 | let changes_found = finder.state_variables_have_been_manipulated();
817 | assert!(changes_found);
818 | assert!(finder.manipulated_storage_pointers.is_empty());
819 | assert_eq!(finder.directly_manipulated_state_variables.len(), 2);
820 | }
821 |
822 | #[test]
823 |
824 | fn test_sv_manipulation_library() {
825 | let context = load_solidity_source_unit(
826 | "../tests/contract-playground/src/StateVariablesManipulation.sol",
827 | );
828 |
829 | let contract = context.find_contract_by_name("SVManipulationLibrary");
830 |
831 | let func = contract.find_function_by_name("manipulateLib");
832 | let func2 = contract.find_function_by_name("manipulateLib2");
833 | let func3 = contract.find_function_by_name("manipulateLib3");
834 |
835 | // Test manipulateLib()
836 | let finder = ApproximateStorageChangeFinder::from(&context, func);
837 | println!("SVManipulationLibrary::manipulateLib()\n{:?}", finder);
838 | let changes_found = finder.state_variables_have_been_manipulated();
839 | assert!(changes_found);
840 | assert_eq!(finder.manipulated_storage_pointers.len(), 1);
841 | assert!(finder.directly_manipulated_state_variables.is_empty());
842 |
843 | // Test manipulateLib2()
844 | let finder = ApproximateStorageChangeFinder::from(&context, func2);
845 | println!("SVManipulationLibrary::manipulateLib2()\n{:?}", finder);
846 | let changes_found = finder.state_variables_have_been_manipulated();
847 | assert!(changes_found);
848 | assert_eq!(finder.manipulated_storage_pointers.len(), 1);
849 | assert!(finder.directly_manipulated_state_variables.is_empty());
850 |
851 | // Test manipulateLib3()
852 | let finder = ApproximateStorageChangeFinder::from(&context, func3);
853 | println!("SVManipulationLibrary::manipulateLib3()\n{:?}", finder);
854 | let changes_found = finder.state_variables_have_been_manipulated();
855 | assert!(changes_found);
856 | assert_eq!(finder.manipulated_storage_pointers.len(), 2);
857 | assert!(finder.directly_manipulated_state_variables.is_empty());
858 | }
859 |
860 | #[test]
861 |
862 | fn test_no_struct_plus_fixed_array_assignment_example() {
863 | let context = load_solidity_source_unit(
864 | "../tests/contract-playground/src/StateVariablesManipulation.sol",
865 | );
866 |
867 | let contract = context.find_contract_by_name("NoStructPlusFixedArrayAssignmentExample");
868 |
869 | let func = contract.find_function_by_name("dontManipulateStateVariables");
870 | let func2 = contract.find_function_by_name("dontManipulateStateVariablesPart2");
871 | let func3 = contract.find_function_by_name("dontManipulateStateVariablesPart3");
872 | let func4 = contract.find_function_by_name("dontManipulateStateVariablesPart4");
873 | let func5 = contract.find_function_by_name("dontManipulateStateVariablesPart5");
874 |
875 | // Test dontManipulateStateVariables()
876 | let finder = ApproximateStorageChangeFinder::from(&context, func);
877 | println!(
878 | "NoStructPlusFixedArrayAssignmentExample::dontManipulateStateVariables()\n{:?}",
879 | finder
880 | );
881 | let no_changes_found = !finder.state_variables_have_been_manipulated();
882 | assert!(no_changes_found);
883 | assert!(finder.manipulated_storage_pointers.is_empty());
884 | assert!(finder.directly_manipulated_state_variables.is_empty());
885 |
886 | // Test dontManipulateStateVariablesPart2()
887 | let finder = ApproximateStorageChangeFinder::from(&context, func2);
888 | println!(
889 | "NoStructPlusFixedArrayAssignmentExample::dontManipulateStateVariablesPart2()\n{:?}",
890 | finder
891 | );
892 | let no_changes_found = !finder.state_variables_have_been_manipulated();
893 | assert!(no_changes_found);
894 | assert!(finder.manipulated_storage_pointers.is_empty());
895 | assert!(finder.directly_manipulated_state_variables.is_empty());
896 |
897 | // Test dontManipulateStateVariablesPart3()
898 | let finder = ApproximateStorageChangeFinder::from(&context, func3);
899 | println!(
900 | "NoStructPlusFixedArrayAssignmentExample::dontManipulateStateVariablesPart3()\n{:?}",
901 | finder
902 | );
903 | let no_changes_found = !finder.state_variables_have_been_manipulated();
904 | assert!(no_changes_found);
905 | assert!(finder.manipulated_storage_pointers.is_empty());
906 | assert!(finder.directly_manipulated_state_variables.is_empty());
907 |
908 | // Test dontManipulateStateVariablesPart4()
909 | let finder = ApproximateStorageChangeFinder::from(&context, func4);
910 | println!(
911 | "NoStructPlusFixedArrayAssignmentExample::dontManipulateStateVariablesPart4()\n{:?}",
912 | finder
913 | );
914 | let no_changes_found = !finder.state_variables_have_been_manipulated();
915 | assert!(no_changes_found);
916 | assert!(finder.manipulated_storage_pointers.is_empty());
917 | assert!(finder.directly_manipulated_state_variables.is_empty());
918 |
919 | // Test dontManipulateStateVariablesPart4()
920 | let finder = ApproximateStorageChangeFinder::from(&context, func5);
921 | println!(
922 | "NoStructPlusFixedArrayAssignmentExample::dontManipulateStateVariablesPart5()\n{:?}",
923 | finder
924 | );
925 | let no_changes_found = !finder.state_variables_have_been_manipulated();
926 | assert!(no_changes_found);
927 | assert!(finder.manipulated_storage_pointers.is_empty());
928 | assert!(finder.directly_manipulated_state_variables.is_empty());
929 | }
930 |
931 | #[test]
932 |
933 | fn test_dynamic_array_push_changes() {
934 | let context = load_solidity_source_unit(
935 | "../tests/contract-playground/src/StateVariablesManipulation.sol",
936 | );
937 |
938 | let contract = context.find_contract_by_name("DynamicArraysPushExample");
939 |
940 | let func = contract.find_function_by_name("manipulateDirectly");
941 | let func2 = contract.find_function_by_name("manipulateViaIndexAccess");
942 | let func3 = contract.find_function_by_name("manipulateViaMemberAccess");
943 | let func4 = contract.find_function_by_name("manipulateViaMemberAccess2");
944 |
945 | // Test manipulateDirectly()
946 | let finder = ApproximateStorageChangeFinder::from(&context, func);
947 | println!("DynamicArraysPushExample::manipulateDirectly()\n{:?}", finder);
948 | let changes_found = finder.state_variables_have_been_manipulated();
949 | assert!(changes_found);
950 | assert!(finder.manipulated_storage_pointers.is_empty());
951 | assert_eq!(finder.directly_manipulated_state_variables.len(), 1);
952 |
953 | // Test manipulateViaIndexAccess()
954 | let finder = ApproximateStorageChangeFinder::from(&context, func2);
955 | println!("DynamicArraysPushExample::manipulateViaIndexAccess()\n{:?}", finder);
956 | let changes_found = finder.state_variables_have_been_manipulated();
957 | assert!(changes_found);
958 | assert!(finder.manipulated_storage_pointers.is_empty());
959 | assert_eq!(finder.directly_manipulated_state_variables.len(), 3);
960 |
961 | // Test manipulateViaMemberAccess()
962 | let finder = ApproximateStorageChangeFinder::from(&context, func3);
963 | println!("DynamicArraysPushExample::manipulateViaMemberAccess()\n{:?}", finder);
964 | let changes_found = finder.state_variables_have_been_manipulated();
965 | assert!(changes_found);
966 | assert!(finder.manipulated_storage_pointers.is_empty());
967 | assert_eq!(finder.directly_manipulated_state_variables.len(), 1);
968 |
969 | // Test manipulateViaMemberAccess2()
970 | let finder = ApproximateStorageChangeFinder::from(&context, func4);
971 | println!("DynamicArraysPushExample::manipulateViaMemberAccess2()\n{:?}", finder);
972 | let changes_found = finder.state_variables_have_been_manipulated();
973 | assert!(changes_found);
974 | assert_eq!(finder.manipulated_storage_pointers.len(), 1); // we only want to capture p1
975 | assert!(finder.directly_manipulated_state_variables.is_empty());
976 | }
977 |
978 | #[test]
979 |
980 | fn test_dynamic_mappings_array_push_changes() {
981 | let context = load_solidity_source_unit(
982 | "../tests/contract-playground/src/StateVariablesManipulation.sol",
983 | );
984 |
985 | let contract = context.find_contract_by_name("DynamicMappingsArrayPushExample");
986 | let func = contract.find_function_by_name("add");
987 |
988 | // Test add()
989 | let finder = ApproximateStorageChangeFinder::from(&context, func);
990 | println!("DynamicMappingsArrayPushExample::add()\n{:?}", finder);
991 | let changes_found = finder.state_variables_have_been_manipulated();
992 | assert!(changes_found);
993 | assert_eq!(finder.directly_manipulated_state_variables.len(), 1);
994 | assert!(finder.manipulated_storage_pointers.is_empty());
995 | }
996 |
997 | #[test]
998 |
999 | fn test_fixed_size_arrays_deletion_example() {
1000 | let context = load_solidity_source_unit(
1001 | "../tests/contract-playground/src/StateVariablesManipulation.sol",
1002 | );
1003 |
1004 | let contract = context.find_contract_by_name("FixedSizeArraysDeletionExample");
1005 | let func = contract.find_function_by_name("manipulateDirectly");
1006 | let func2 = contract.find_function_by_name("manipulateViaIndexAccess");
1007 |
1008 | // Test func()
1009 | let finder = ApproximateStorageChangeFinder::from(&context, func);
1010 | println!("FixedSizeArraysDeletionExample::manipulateDirectly()\n{:?}", finder);
1011 | let changes_found = finder.state_variables_have_been_manipulated();
1012 | assert!(changes_found);
1013 | assert_eq!(finder.directly_manipulated_state_variables.len(), 1);
1014 | assert!(finder.manipulated_storage_pointers.is_empty());
1015 |
1016 | // Test func2()
1017 | let finder = ApproximateStorageChangeFinder::from(&context, func2);
1018 | println!("FixedSizeArraysDeletionExample::manipulateViaIndexAccess()\n{:?}", finder);
1019 | let changes_found = finder.state_variables_have_been_manipulated();
1020 | assert!(changes_found);
1021 | assert_eq!(finder.directly_manipulated_state_variables.len(), 2);
1022 | assert!(finder.manipulated_storage_pointers.is_empty());
1023 | }
1024 | }
1025 |
```