This is page 87 of 94. Use http://codebase.md/cyfrin/aderyn?lines=false&page={x} to view the full context.
# Directory Structure
```
├── .cargo
│ └── config.toml
├── .git-blame-ignore-revs
├── .gitattributes
├── .github
│ ├── images
│ │ ├── aderyn_logo.png
│ │ ├── poweredbycyfrinblack.png
│ │ └── poweredbycyfrinblue.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ ├── false_positive_issue.md
│ │ └── feature_request.md
│ └── workflows
│ ├── cargo.yml
│ ├── dependencies.yml
│ ├── release.yml
│ ├── reports.yml
│ └── toml.yml
├── .gitignore
├── .gitmodules
├── .vscode
│ └── settings.json
├── aderyn
│ ├── Cargo.toml
│ ├── oranda.json
│ ├── README.md
│ ├── src
│ │ ├── birdsong.rs
│ │ ├── completions.rs
│ │ ├── lib.rs
│ │ ├── lsp.rs
│ │ ├── main.rs
│ │ ├── mcp.rs
│ │ └── panic.rs
│ └── templates
│ └── aderyn.toml
├── aderyn_core
│ ├── .gitignore
│ ├── Cargo.toml
│ ├── README.md
│ ├── src
│ │ ├── ast
│ │ │ ├── ast_nodes.rs
│ │ │ ├── ast.rs
│ │ │ ├── impls
│ │ │ │ ├── ctx
│ │ │ │ │ ├── utils.rs
│ │ │ │ │ └── workspace.rs
│ │ │ │ ├── ctx.rs
│ │ │ │ ├── disp
│ │ │ │ │ ├── blocks.rs
│ │ │ │ │ ├── contracts.rs
│ │ │ │ │ ├── enumerations.rs
│ │ │ │ │ ├── errors.rs
│ │ │ │ │ ├── events.rs
│ │ │ │ │ ├── expressions.rs
│ │ │ │ │ ├── functions.rs
│ │ │ │ │ ├── identifiers.rs
│ │ │ │ │ ├── literals.rs
│ │ │ │ │ ├── modifiers.rs
│ │ │ │ │ ├── statements.rs
│ │ │ │ │ ├── structures.rs
│ │ │ │ │ ├── types.rs
│ │ │ │ │ ├── user_defined_value_types.rs
│ │ │ │ │ ├── using_for_directives.rs
│ │ │ │ │ └── variables.rs
│ │ │ │ ├── disp.rs
│ │ │ │ ├── node
│ │ │ │ │ ├── blocks.rs
│ │ │ │ │ ├── contracts.rs
│ │ │ │ │ ├── documentation.rs
│ │ │ │ │ ├── enumerations.rs
│ │ │ │ │ ├── errors.rs
│ │ │ │ │ ├── events.rs
│ │ │ │ │ ├── expressions.rs
│ │ │ │ │ ├── functions.rs
│ │ │ │ │ ├── identifiers.rs
│ │ │ │ │ ├── import_directives.rs
│ │ │ │ │ ├── literals.rs
│ │ │ │ │ ├── modifiers.rs
│ │ │ │ │ ├── pragma_directives.rs
│ │ │ │ │ ├── source_units.rs
│ │ │ │ │ ├── statements.rs
│ │ │ │ │ ├── structures.rs
│ │ │ │ │ ├── types.rs
│ │ │ │ │ ├── user_defined_value_types.rs
│ │ │ │ │ ├── using_for_directives.rs
│ │ │ │ │ └── variables.rs
│ │ │ │ ├── node.rs
│ │ │ │ ├── own
│ │ │ │ │ ├── hashing.rs
│ │ │ │ │ ├── node_id.rs
│ │ │ │ │ ├── source_units.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ └── own.rs
│ │ │ ├── impls.rs
│ │ │ ├── macros.rs
│ │ │ ├── magic.rs
│ │ │ ├── node_type.rs
│ │ │ └── yul.rs
│ │ ├── ast.rs
│ │ ├── audit
│ │ │ ├── attack_surface.rs
│ │ │ ├── auditor.rs
│ │ │ ├── entrypoint.rs
│ │ │ └── public_functions_no_sender.rs
│ │ ├── audit.rs
│ │ ├── context
│ │ │ ├── browser
│ │ │ │ ├── ancestral_line.rs
│ │ │ │ ├── closest_ancestor.rs
│ │ │ │ ├── external_calls.rs
│ │ │ │ ├── extractor.rs
│ │ │ │ ├── immediate_children.rs
│ │ │ │ ├── location.rs
│ │ │ │ ├── macros.rs
│ │ │ │ ├── parent.rs
│ │ │ │ ├── peek_over.rs
│ │ │ │ ├── peek_under.rs
│ │ │ │ ├── peek.rs
│ │ │ │ ├── siblings.rs
│ │ │ │ ├── sort_nodes.rs
│ │ │ │ └── storage_vars.rs
│ │ │ ├── browser.rs
│ │ │ ├── capturable.rs
│ │ │ ├── flow
│ │ │ │ ├── display.rs
│ │ │ │ ├── error.rs
│ │ │ │ ├── kind.rs
│ │ │ │ ├── primitives.rs
│ │ │ │ ├── reducibles.rs
│ │ │ │ ├── tests.rs
│ │ │ │ ├── utils.rs
│ │ │ │ ├── visualizer.rs
│ │ │ │ └── voids.rs
│ │ │ ├── flow.rs
│ │ │ ├── graph
│ │ │ │ ├── callgraph
│ │ │ │ │ ├── legacy.rs
│ │ │ │ │ ├── new.rs
│ │ │ │ │ ├── tests.rs
│ │ │ │ │ ├── utils.rs
│ │ │ │ │ └── visit.rs
│ │ │ │ ├── callgraph.rs
│ │ │ │ ├── preprocess
│ │ │ │ │ ├── legacy.rs
│ │ │ │ │ └── new.rs
│ │ │ │ ├── preprocess.rs
│ │ │ │ ├── traits.rs
│ │ │ │ └── utils.rs
│ │ │ ├── graph.rs
│ │ │ ├── macros.rs
│ │ │ ├── mcp
│ │ │ │ ├── callgraph
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ ├── callgraph.rs
│ │ │ │ ├── contract_surface
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── util.rs
│ │ │ │ ├── contract_surface.rs
│ │ │ │ ├── list_contracts
│ │ │ │ │ ├── render.rs
│ │ │ │ │ └── tool.rs
│ │ │ │ ├── list_contracts.rs
│ │ │ │ ├── node_finder
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ ├── node_finder.rs
│ │ │ │ ├── node_summarizer
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ ├── node_summarizer.rs
│ │ │ │ ├── project_overview
│ │ │ │ │ ├── render.rs
│ │ │ │ │ └── tool.rs
│ │ │ │ ├── project_overview.rs
│ │ │ │ ├── tool_guide
│ │ │ │ │ └── tool.rs
│ │ │ │ └── tool_guide.rs
│ │ │ ├── mcp.rs
│ │ │ ├── router
│ │ │ │ ├── external_calls.rs
│ │ │ │ ├── internal_calls.rs
│ │ │ │ ├── modifier_calls.rs
│ │ │ │ └── tests.rs
│ │ │ ├── router.rs
│ │ │ └── workspace.rs
│ │ ├── context.rs
│ │ ├── detect
│ │ │ ├── detector.rs
│ │ │ ├── entrypoint.rs
│ │ │ ├── helpers.rs
│ │ │ ├── high
│ │ │ │ ├── _template.rs
│ │ │ │ ├── abi_encode_packed_hash_collision.rs
│ │ │ │ ├── arbitrary_transfer_from.rs
│ │ │ │ ├── const_func_changes_state.rs
│ │ │ │ ├── contract_locks_ether.rs
│ │ │ │ ├── dangerous_unary_operator.rs
│ │ │ │ ├── delegate_call_unchecked_address.rs
│ │ │ │ ├── delete_nested_mapping.rs
│ │ │ │ ├── dynamic_array_length_assignment.rs
│ │ │ │ ├── enumerable_loop_removal.rs
│ │ │ │ ├── eth_send_unchecked_address.rs
│ │ │ │ ├── experimental_encoder.rs
│ │ │ │ ├── function_selector_collision.rs
│ │ │ │ ├── incorrect_caret_operator.rs
│ │ │ │ ├── incorrect_erc20_interface.rs
│ │ │ │ ├── incorrect_erc721_interface.rs
│ │ │ │ ├── incorrect_shift_order.rs
│ │ │ │ ├── misused_boolean.rs
│ │ │ │ ├── msg_value_in_loops.rs
│ │ │ │ ├── multiple_constructors.rs
│ │ │ │ ├── nested_struct_in_mapping.rs
│ │ │ │ ├── out_of_order_retryable.rs
│ │ │ │ ├── pre_declared_variable_usage.rs
│ │ │ │ ├── reentrancy_state_change.rs
│ │ │ │ ├── reused_contract_name.rs
│ │ │ │ ├── rtlo.rs
│ │ │ │ ├── selfdestruct.rs
│ │ │ │ ├── signed_integer_storage_array.rs
│ │ │ │ ├── state_variable_shadowing.rs
│ │ │ │ ├── storage_array_memory_edit.rs
│ │ │ │ ├── strict_equality_contract_balance.rs
│ │ │ │ ├── tautological_compare.rs
│ │ │ │ ├── tautology_or_contradiction.rs
│ │ │ │ ├── tx_origin_used_for_auth.rs
│ │ │ │ ├── unchecked_low_level_call.rs
│ │ │ │ ├── unchecked_send.rs
│ │ │ │ ├── unprotected_initializer.rs
│ │ │ │ ├── unsafe_casting.rs
│ │ │ │ ├── weak_randomness.rs
│ │ │ │ └── yul_return.rs
│ │ │ ├── high.rs
│ │ │ ├── low
│ │ │ │ ├── _template.rs
│ │ │ │ ├── assert_state_change.rs
│ │ │ │ ├── block_timestamp_deadline.rs
│ │ │ │ ├── boolean_equality.rs
│ │ │ │ ├── builtin_symbol_shadowing.rs
│ │ │ │ ├── centralization_risk.rs
│ │ │ │ ├── constant_function_contains_assembly.rs
│ │ │ │ ├── costly_loop.rs
│ │ │ │ ├── dead_code.rs
│ │ │ │ ├── delegatecall_in_loop.rs
│ │ │ │ ├── deprecated_oz_function.rs
│ │ │ │ ├── division_before_multiplication.rs
│ │ │ │ ├── ecrecover.rs
│ │ │ │ ├── empty_block.rs
│ │ │ │ ├── empty_require_revert.rs
│ │ │ │ ├── function_initializing_state.rs
│ │ │ │ ├── function_pointer_in_constructor.rs
│ │ │ │ ├── inconsistent_type_names.rs
│ │ │ │ ├── incorrect_modifier.rs
│ │ │ │ ├── internal_function_used_once.rs
│ │ │ │ ├── large_numeric_literal.rs
│ │ │ │ ├── literal_instead_of_constant.rs
│ │ │ │ ├── local_variable_shadowing.rs
│ │ │ │ ├── missing_inheritance.rs
│ │ │ │ ├── modifier_used_only_once.rs
│ │ │ │ ├── multiple_placeholders.rs
│ │ │ │ ├── non_reentrant_not_first.rs
│ │ │ │ ├── push_0_opcode.rs
│ │ │ │ ├── redundant_statement.rs
│ │ │ │ ├── require_revert_in_loop.rs
│ │ │ │ ├── return_bomb.rs
│ │ │ │ ├── solmate_safe_transfer_lib.rs
│ │ │ │ ├── state_change_without_event.rs
│ │ │ │ ├── state_no_address_check.rs
│ │ │ │ ├── state_variable_could_be_constant.rs
│ │ │ │ ├── state_variable_could_be_immutable.rs
│ │ │ │ ├── state_variable_read_external.rs
│ │ │ │ ├── storage_array_length_not_cached.rs
│ │ │ │ ├── todo.rs
│ │ │ │ ├── unchecked_return.rs
│ │ │ │ ├── uninitialized_local_variable.rs
│ │ │ │ ├── unsafe_erc20_operation.rs
│ │ │ │ ├── unsafe_oz_erc721_mint.rs
│ │ │ │ ├── unspecific_solidity_pragma.rs
│ │ │ │ ├── unused_error.rs
│ │ │ │ ├── unused_import.rs
│ │ │ │ ├── unused_public_function.rs
│ │ │ │ ├── unused_state_variable.rs
│ │ │ │ └── void_constructor.rs
│ │ │ ├── low.rs
│ │ │ └── test_utils.rs
│ │ ├── detect.rs
│ │ ├── lib.rs
│ │ ├── stats
│ │ │ ├── cloc.rs
│ │ │ ├── dbg_tips.txt
│ │ │ ├── ignore.rs
│ │ │ ├── token.rs
│ │ │ └── util.rs
│ │ ├── stats.rs
│ │ ├── test_utils
│ │ │ └── load_source_unit.rs
│ │ ├── test_utils.rs
│ │ ├── visitor
│ │ │ ├── ast_visitor.rs
│ │ │ ├── macros.rs
│ │ │ └── workspace_visitor.rs
│ │ └── visitor.rs
│ ├── templates
│ │ └── mcp-tool-response
│ │ ├── callgraph.md
│ │ ├── contract_surface.md
│ │ ├── list_contracts.md
│ │ ├── node_finder_get_all.md
│ │ ├── node_finder_grep.md
│ │ ├── node_finder_search.md
│ │ ├── node_summarizer.md
│ │ ├── project_overview.md
│ │ └── tool_guide.md
│ └── tests
│ ├── common
│ │ ├── ancestral_line.rs
│ │ ├── closest_ancestor.rs
│ │ ├── immediate_children.rs
│ │ ├── immediate_parent.rs
│ │ ├── mod.rs
│ │ ├── new_ast_nodes.rs
│ │ ├── peek_over.rs
│ │ └── sibling.rs
│ └── traversal.rs
├── aderyn_driver
│ ├── .gitignore
│ ├── benches
│ │ └── detectors.rs
│ ├── Cargo.toml
│ ├── README.md
│ ├── src
│ │ ├── compile.rs
│ │ ├── config.rs
│ │ ├── display.rs
│ │ ├── driver.rs
│ │ ├── interface
│ │ │ ├── json.rs
│ │ │ ├── lsp.rs
│ │ │ ├── markdown.rs
│ │ │ ├── mod.rs
│ │ │ ├── sarif.rs
│ │ │ ├── tables.rs
│ │ │ └── util.rs
│ │ ├── lib.rs
│ │ ├── mcp.rs
│ │ ├── process.rs
│ │ └── runner.rs
│ └── tests
│ └── astgen.rs
├── bacon.toml
├── benchmarks
│ ├── aderyn
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── iteration_times.svg
│ │ │ └── pdf.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── iteration_times_small.svg
│ │ ├── iteration_times.svg
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── relative_iteration_times_small.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── SD.svg
│ │ └── typical.svg
│ ├── arbitrary-transfer-from
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── avoid-abi-encode-packed
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── block-timestamp-deadline
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── centralization-risk
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── constants-instead-of-literals
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── delegate-call-in-loop
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── deprecated-oz-functions
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── ecrecover
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── empty-block
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── hello_world
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── inconsistent-type-names
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── large-numeric-literal
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── non-reentrant-before-others
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── push-zero-opcode
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── report
│ │ └── index.html
│ ├── require-with-string
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── solmate-safe-transfer-lib
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unindexed-events
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unprotected-initializer
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unsafe-erc20-functions
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unsafe-oz-erc721-mint
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unspecific-solidity-pragma
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── useless-internal-function
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── useless-modifier
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── useless-public-function
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ └── zero-address-check
│ ├── base
│ │ ├── benchmark.json
│ │ ├── estimates.json
│ │ ├── sample.json
│ │ └── tukey.json
│ ├── change
│ │ └── estimates.json
│ ├── new
│ │ ├── benchmark.json
│ │ ├── estimates.json
│ │ ├── sample.json
│ │ └── tukey.json
│ └── report
│ ├── both
│ │ ├── pdf.svg
│ │ └── regression.svg
│ ├── change
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ └── t-test.svg
│ ├── index.html
│ ├── MAD.svg
│ ├── mean.svg
│ ├── median.svg
│ ├── pdf_small.svg
│ ├── pdf.svg
│ ├── regression_small.svg
│ ├── regression.svg
│ ├── relative_pdf_small.svg
│ ├── relative_regression_small.svg
│ ├── SD.svg
│ ├── slope.svg
│ └── typical.svg
├── Cargo.lock
├── Cargo.toml
├── cli
│ ├── benchmarks.sh
│ └── reportgen.sh
├── CODEOWNERS
├── CONTRIBUTING.md
├── cyfrinup
│ ├── dynamic_script
│ └── why.md
├── deny.toml
├── dist-workspace.toml
├── funding.json
├── LICENSE
├── Makefile
├── package-lock.json
├── package.json
├── README.md
├── RELEASE_CHECKLIST.md
├── reports
│ ├── adhoc-sol-files-highs-only-report.json
│ ├── adhoc-sol-files-report.md
│ ├── ccip-functions-report.md
│ ├── empty_report.md
│ ├── hardhat-playground-report.md
│ ├── nft-report-icm.md
│ ├── nft-report.md
│ ├── prb-math-report.md
│ ├── report.json
│ ├── report.md
│ ├── report.sarif
│ ├── sablier-aderyn-toml-nested-root.md
│ ├── templegold-report.md
│ └── uniswap_profile.md
├── rust-toolchain.toml
├── rustfmt.toml
├── tests
│ ├── adhoc-sol-files
│ │ ├── aderyn.toml
│ │ ├── Counter.sol
│ │ ├── DemoASTNodes.sol
│ │ ├── Helper.sol
│ │ ├── InconsistentUints.sol
│ │ ├── inheritance
│ │ │ ├── ExtendedInheritance.sol
│ │ │ ├── IContractInheritance.sol
│ │ │ └── InheritanceBase.sol
│ │ ├── InternalFunctions.sol
│ │ ├── lib
│ │ │ └── ThisShouldBeExcluded.sol
│ │ ├── multiple-versions
│ │ │ ├── 0.4
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ ├── 0.5
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ ├── 0.6
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ ├── 0.7
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ └── 0.8
│ │ │ ├── A.sol
│ │ │ └── B.sol
│ │ ├── OnceModifierExample.sol
│ │ └── StateVariables.sol
│ ├── ast
│ │ ├── abstract_contract.json
│ │ ├── address_payable.json
│ │ ├── array_type_name.json
│ │ ├── ast-erc4626.json
│ │ ├── base_constructor_call.json
│ │ ├── bit_not.json
│ │ ├── call.json
│ │ ├── constructor.json
│ │ ├── contract_dep_order.json
│ │ ├── do_while.json
│ │ ├── documentation_1.json
│ │ ├── documentation_2.json
│ │ ├── documentation_3.json
│ │ ├── documentation_local_variable.json
│ │ ├── documentation_on_statements.json
│ │ ├── documentation_triple.json
│ │ ├── empty_block.json
│ │ ├── enum_value_declaration.json
│ │ ├── enum_value.json
│ │ ├── event_definition.json
│ │ ├── experimental_encoder_pragma.json
│ │ ├── fallback_and_reveice_ether.json
│ │ ├── fallback_payable.json
│ │ ├── fallback.json
│ │ ├── function_type.json
│ │ ├── function.json
│ │ ├── global_enum.json
│ │ ├── global_struct.json
│ │ ├── inheritance_specifier.json
│ │ ├── leave.json
│ │ ├── license.json
│ │ ├── long_type_name_binary_operation.json
│ │ ├── long_type_name_identifier.json
│ │ ├── loop.json
│ │ ├── mappings.json
│ │ ├── modifier_definition.json
│ │ ├── modifier_invocation.json
│ │ ├── mutability.json
│ │ ├── nested_functions.json
│ │ ├── non_utf8.json
│ │ ├── override.json
│ │ ├── placeholder_statement.json
│ │ ├── receive_ether.json
│ │ ├── short_type_name_ref.json
│ │ ├── short_type_name.json
│ │ ├── slot_offset.json
│ │ ├── smoke.json
│ │ ├── source_location.json
│ │ ├── string.json
│ │ ├── stringlit.json
│ │ ├── switch_default.json
│ │ ├── switch.json
│ │ ├── try_catch.json
│ │ ├── two_base_functions.json
│ │ ├── unicode.json
│ │ ├── used_errors.json
│ │ ├── userDefinedValueType.json
│ │ ├── using_for_directive.json
│ │ ├── var_access.json
│ │ └── yul_hex_literal.json
│ ├── contract-playground
│ │ ├── .github
│ │ │ └── workflows
│ │ │ └── test.yml
│ │ ├── .gitignore
│ │ ├── dot
│ │ │ └── .gitkeep
│ │ ├── foundry.toml
│ │ ├── README.md
│ │ ├── script
│ │ │ └── Counter.s.sol
│ │ ├── src
│ │ │ ├── AbstractContract.sol
│ │ │ ├── AderynIgnoreCustomDetectors.sol
│ │ │ ├── AdminContract.sol
│ │ │ ├── ArbitraryTransferFrom.sol
│ │ │ ├── AssemblyExample.sol
│ │ │ ├── AssertStateChange.sol
│ │ │ ├── auditor_mode
│ │ │ │ ├── ExternalCalls.sol
│ │ │ │ └── PublicFunctionsWithoutSenderCheck.sol
│ │ │ ├── BooleanEquality.sol
│ │ │ ├── BuiltinSymbolShadow.sol
│ │ │ ├── CacheArrayLength.sol
│ │ │ ├── CallGraphTests.sol
│ │ │ ├── Casting.sol
│ │ │ ├── cloc
│ │ │ │ ├── AnotherHeavilyCommentedContract.sol
│ │ │ │ ├── EmptyContractFile.sol
│ │ │ │ └── HeavilyCommentedContract.sol
│ │ │ ├── CompilerBugStorageSignedIntegerArray.sol
│ │ │ ├── ConstantFuncsAssembly.sol
│ │ │ ├── ConstantsLiterals.sol
│ │ │ ├── ConstFuncChangeState.sol
│ │ │ ├── ContractLocksEther.sol
│ │ │ ├── ContractWithTodo.sol
│ │ │ ├── control_flow
│ │ │ │ └── SimpleProgram.sol
│ │ │ ├── CostlyOperationsInsideLoops.sol
│ │ │ ├── Counter.sol
│ │ │ ├── CrazyPragma.sol
│ │ │ ├── DangerousStrictEquality1.sol
│ │ │ ├── DangerousStrictEquality2.sol
│ │ │ ├── DangerousUnaryOperator.sol
│ │ │ ├── DeadCode.sol
│ │ │ ├── DelegateCallWithoutAddressCheck.sol
│ │ │ ├── DeletionNestedMappingStructureContract.sol
│ │ │ ├── DeprecatedOZFunctions.sol
│ │ │ ├── DivisionBeforeMultiplication.sol
│ │ │ ├── DynamicArrayLengthAssignment.sol
│ │ │ ├── EmitAfterExternalCall.sol
│ │ │ ├── EmptyBlocks.sol
│ │ │ ├── EnumerableSetIteration.sol
│ │ │ ├── eth2
│ │ │ │ └── DepositContract.sol
│ │ │ ├── ExperimentalEncoder.sol
│ │ │ ├── ExternalCalls.sol
│ │ │ ├── FunctionInitializingState.sol
│ │ │ ├── FunctionPointers.sol
│ │ │ ├── FunctionSignatureCollision.sol
│ │ │ ├── HugeConstants.sol
│ │ │ ├── IgnoreEverything.sol
│ │ │ ├── InconsistentUints.sol
│ │ │ ├── IncorrectCaretOperator.sol
│ │ │ ├── IncorrectERC20.sol
│ │ │ ├── IncorrectERC721.sol
│ │ │ ├── IncorrectModifier.sol
│ │ │ ├── IncorrectShift.sol
│ │ │ ├── inheritance
│ │ │ │ ├── ExtendedInheritance.sol
│ │ │ │ ├── IContractInheritance.sol
│ │ │ │ └── InheritanceBase.sol
│ │ │ ├── InternalFunctions.sol
│ │ │ ├── KeccakContract.sol
│ │ │ ├── LocalVariableShadow.sol
│ │ │ ├── MissingInheritance.sol
│ │ │ ├── MisusedBoolean.sol
│ │ │ ├── MsgValueInLoop.sol
│ │ │ ├── MultipleConstructorSchemes.sol
│ │ │ ├── MultiplePlaceholders.sol
│ │ │ ├── nested
│ │ │ │ ├── 1
│ │ │ │ │ └── Nested.sol
│ │ │ │ └── 2
│ │ │ │ └── Nested.sol
│ │ │ ├── nested_mappings
│ │ │ │ ├── LaterVersion.sol
│ │ │ │ └── NestedMappings.sol
│ │ │ ├── OnceModifierExample.sol
│ │ │ ├── OnlyLibrary.sol
│ │ │ ├── OutOfOrderRetryable.sol
│ │ │ ├── parent_chain
│ │ │ │ └── ParentChainContract.sol
│ │ │ ├── PragmaRange.sol
│ │ │ ├── PreDeclaredVarUsage.sol
│ │ │ ├── PublicFunction.sol
│ │ │ ├── PublicVariableReadInExternalContext.sol
│ │ │ ├── RedundantStatements.sol
│ │ │ ├── ReturnBomb.sol
│ │ │ ├── reused_contract_name
│ │ │ │ ├── ContractA.sol
│ │ │ │ └── ContractB.sol
│ │ │ ├── RevertsAndRequriesInLoops.sol
│ │ │ ├── router
│ │ │ │ ├── ExternalCalls.sol
│ │ │ │ ├── FallbackAndReceiveOverrides.sol
│ │ │ │ ├── InternalCalls.sol
│ │ │ │ ├── ModifierCalls.sol
│ │ │ │ └── VarOverridesFunction.sol
│ │ │ ├── RTLO.sol
│ │ │ ├── SendEtherNoChecks.sol
│ │ │ ├── SendEtherNoChecksLibImport.sol
│ │ │ ├── StateChangeAfterExternalCall.sol
│ │ │ ├── StateShadowing.sol
│ │ │ ├── StateVariableCouldBeDeclaredConstant.sol
│ │ │ ├── StateVariableCouldBeDeclaredImmutable.sol
│ │ │ ├── StateVariables.sol
│ │ │ ├── StateVariablesChangesWithoutEvents.sol
│ │ │ ├── StateVariablesManipulation.sol
│ │ │ ├── StorageConditionals.sol
│ │ │ ├── StorageParameters.sol
│ │ │ ├── T11sTranferer.sol
│ │ │ ├── TautologicalCompare.sol
│ │ │ ├── TautologyOrContradiction.sol
│ │ │ ├── TestERC20.sol
│ │ │ ├── TransientKeyword.sol
│ │ │ ├── Trump.sol
│ │ │ ├── TxOriginUsedForAuth.sol
│ │ │ ├── U2.sol
│ │ │ ├── U3.sol
│ │ │ ├── U4.sol
│ │ │ ├── U5.sol
│ │ │ ├── UncheckedCalls.sol
│ │ │ ├── UncheckedReturn.sol
│ │ │ ├── UncheckedSend.sol
│ │ │ ├── UninitializedLocalVariables.sol
│ │ │ ├── UninitializedStateVariable.sol
│ │ │ ├── uniswap
│ │ │ │ ├── UniswapV2Swapper.sol
│ │ │ │ └── UniswapV3Swapper.sol
│ │ │ ├── UnprotectedInitialize.sol
│ │ │ ├── UnsafeERC721Mint.sol
│ │ │ ├── UnusedError.sol
│ │ │ ├── UnusedImport.sol
│ │ │ ├── UnusedStateVariables.sol
│ │ │ ├── UsingSelfdestruct.sol
│ │ │ ├── VoidConstructor.sol
│ │ │ ├── WeakRandomness.sol
│ │ │ ├── WrongOrderOfLayout.sol
│ │ │ ├── YulReturn.sol
│ │ │ └── ZeroAddressCheck.sol
│ │ └── test
│ │ └── Counter.t.sol
│ ├── foundry-nft-f23
│ │ ├── .github
│ │ │ └── workflows
│ │ │ └── test.yml
│ │ ├── .gitignore
│ │ ├── foundry.lock
│ │ ├── foundry.toml
│ │ ├── README.md
│ │ ├── remappings.txt
│ │ └── src
│ │ ├── BasicNft.sol
│ │ ├── F1.sol
│ │ ├── F2.sol
│ │ ├── Initializer.sol
│ │ └── inner-core-modules
│ │ └── ICM.sol
│ ├── foundry-nft-f23-icm
│ │ ├── .github
│ │ │ └── workflows
│ │ │ └── test.yml
│ │ ├── .gitignore
│ │ ├── aderyn.toml
│ │ ├── foundry.toml
│ │ ├── README.md
│ │ ├── remappings.txt
│ │ └── src
│ │ ├── BasicNft.sol
│ │ ├── F1.sol
│ │ ├── F2.sol
│ │ ├── Initializer.sol
│ │ └── inner-core-modules
│ │ └── ICM.sol
│ ├── hardhat-js-playground
│ │ ├── .gitignore
│ │ ├── artifacts
│ │ │ ├── build-info
│ │ │ │ └── cee6fe9a9a2f03f7ff10a27ab2746af6.json
│ │ │ └── contracts
│ │ │ ├── Counter.sol
│ │ │ │ ├── Counter.dbg.json
│ │ │ │ └── Counter.json
│ │ │ ├── ExtendedInheritance.sol
│ │ │ │ ├── ExtendedInheritance.dbg.json
│ │ │ │ └── ExtendedInheritance.json
│ │ │ ├── IContractInheritance.sol
│ │ │ │ ├── IContractInheritance.dbg.json
│ │ │ │ └── IContractInheritance.json
│ │ │ ├── InheritanceBase.sol
│ │ │ │ ├── InheritanceBase.dbg.json
│ │ │ │ └── InheritanceBase.json
│ │ │ ├── KeccakContract.sol
│ │ │ │ ├── KeccakContract.dbg.json
│ │ │ │ └── KeccakContract.json
│ │ │ ├── Lock.sol
│ │ │ │ ├── Lock.dbg.json
│ │ │ │ └── Lock.json
│ │ │ └── StateVariables.sol
│ │ │ ├── StateVariables.dbg.json
│ │ │ └── StateVariables.json
│ │ ├── contracts
│ │ │ ├── Counter.sol
│ │ │ ├── ExtendedInheritance.sol
│ │ │ ├── IContractInheritance.sol
│ │ │ ├── InheritanceBase.sol
│ │ │ ├── KeccakContract.sol
│ │ │ ├── Lock.sol
│ │ │ └── StateVariables.sol
│ │ ├── hardhat.config.js
│ │ ├── package.json
│ │ ├── README.md
│ │ ├── scripts
│ │ │ └── deploy.js
│ │ ├── test
│ │ │ └── Lock.js
│ │ └── yarn.lock
│ ├── no-sol-files
│ │ ├── extra
│ │ │ └── HelloAgain.md
│ │ ├── Hello.txt
│ │ └── Hello.yul
│ └── toml
│ ├── nested_project1
│ │ ├── aderyn.toml
│ │ ├── folder1
│ │ │ └── hardhat.config.ts
│ │ ├── folder2
│ │ │ └── hardhat.config.ts
│ │ └── folder3
│ │ └── file.txt
│ └── nested_project2
│ ├── aderyn.toml
│ ├── folder1
│ │ └── foundry.toml
│ └── folder2
│ └── file1.txt
├── tools
│ └── xtask
│ ├── Cargo.toml
│ └── src
│ ├── blesspr.rs
│ ├── cut_release.rs
│ ├── flags.rs
│ ├── main.rs
│ ├── reportgen.rs
│ └── tomlgen.rs
└── typos.toml
```
# Files
--------------------------------------------------------------------------------
/aderyn_core/src/visitor/ast_visitor.rs:
--------------------------------------------------------------------------------
```rust
use eyre::Result;
use crate::ast::*;
pub trait ASTConstVisitor {
fn visit_array_type_name(&mut self, node: &ArrayTypeName) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_array_type_name(&mut self, node: &ArrayTypeName) -> Result<()> {
self.end_visit_node(node)
}
fn visit_assignment(&mut self, node: &Assignment) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_assignment(&mut self, node: &Assignment) -> Result<()> {
self.end_visit_node(node)
}
fn visit_binary_operation(&mut self, node: &BinaryOperation) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_binary_operation(&mut self, node: &BinaryOperation) -> Result<()> {
self.end_visit_node(node)
}
fn visit_block(&mut self, node: &Block) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_block(&mut self, node: &Block) -> Result<()> {
self.end_visit_node(node)
}
fn visit_unchecked_block(&mut self, node: &UncheckedBlock) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_unchecked_block(&mut self, node: &UncheckedBlock) -> Result<()> {
self.end_visit_node(node)
}
fn visit_conditional(&mut self, node: &Conditional) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_conditional(&mut self, node: &Conditional) -> Result<()> {
self.end_visit_node(node)
}
fn visit_contract_definition(&mut self, node: &ContractDefinition) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_contract_definition(&mut self, node: &ContractDefinition) -> Result<()> {
self.end_visit_node(node)
}
fn visit_elementary_type_name(&mut self, node: &ElementaryTypeName) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_elementary_type_name(&mut self, node: &ElementaryTypeName) -> Result<()> {
self.end_visit_node(node)
}
fn visit_elementary_type_name_expression(
&mut self,
node: &ElementaryTypeNameExpression,
) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_elementary_type_name_expression(
&mut self,
node: &ElementaryTypeNameExpression,
) -> Result<()> {
self.end_visit_node(node)
}
fn visit_emit_statement(&mut self, node: &EmitStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_emit_statement(&mut self, node: &EmitStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_enum_definition(&mut self, node: &EnumDefinition) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_enum_definition(&mut self, node: &EnumDefinition) -> Result<()> {
self.end_visit_node(node)
}
fn visit_enum_value(&mut self, node: &EnumValue) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_enum_value(&mut self, node: &EnumValue) -> Result<()> {
self.end_visit_node(node)
}
fn visit_event_definition(&mut self, node: &EventDefinition) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_event_definition(&mut self, node: &EventDefinition) -> Result<()> {
self.end_visit_node(node)
}
fn visit_error_definition(&mut self, node: &ErrorDefinition) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_error_definition(&mut self, node: &ErrorDefinition) -> Result<()> {
self.end_visit_node(node)
}
fn visit_expression_statement(&mut self, node: &ExpressionStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_expression_statement(&mut self, node: &ExpressionStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_function_call(&mut self, node: &FunctionCall) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_function_call(&mut self, node: &FunctionCall) -> Result<()> {
self.end_visit_node(node)
}
fn visit_function_call_options(&mut self, node: &FunctionCallOptions) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_function_call_options(&mut self, node: &FunctionCallOptions) -> Result<()> {
self.end_visit_node(node)
}
fn visit_function_definition(&mut self, node: &FunctionDefinition) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_function_definition(&mut self, node: &FunctionDefinition) -> Result<()> {
self.end_visit_node(node)
}
fn visit_function_type_name(&mut self, node: &FunctionTypeName) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_function_type_name(&mut self, node: &FunctionTypeName) -> Result<()> {
self.end_visit_node(node)
}
fn visit_for_statement(&mut self, node: &ForStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_for_statement(&mut self, node: &ForStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_identifier(&mut self, node: &Identifier) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_identifier(&mut self, node: &Identifier) -> Result<()> {
self.end_visit_node(node)
}
fn visit_identifier_path(&mut self, node: &IdentifierPath) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_identifier_path(&mut self, node: &IdentifierPath) -> Result<()> {
self.end_visit_node(node)
}
fn visit_if_statement(&mut self, node: &IfStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_if_statement(&mut self, node: &IfStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_import_directive(&mut self, node: &ImportDirective) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_import_directive(&mut self, node: &ImportDirective) -> Result<()> {
self.end_visit_node(node)
}
fn visit_index_access(&mut self, node: &IndexAccess) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_index_access(&mut self, node: &IndexAccess) -> Result<()> {
self.end_visit_node(node)
}
fn visit_index_range_access(&mut self, node: &IndexRangeAccess) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_index_range_access(&mut self, node: &IndexRangeAccess) -> Result<()> {
self.end_visit_node(node)
}
fn visit_inheritance_specifier(&mut self, node: &InheritanceSpecifier) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_inheritance_specifier(&mut self, node: &InheritanceSpecifier) -> Result<()> {
self.end_visit_node(node)
}
fn visit_inline_assembly(&mut self, node: &InlineAssembly) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_inline_assembly(&mut self, node: &InlineAssembly) -> Result<()> {
self.end_visit_node(node)
}
fn visit_literal(&mut self, node: &Literal) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_literal(&mut self, node: &Literal) -> Result<()> {
self.end_visit_node(node)
}
fn visit_member_access(&mut self, node: &MemberAccess) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_member_access(&mut self, node: &MemberAccess) -> Result<()> {
self.end_visit_node(node)
}
fn visit_new_expression(&mut self, node: &NewExpression) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_new_expression(&mut self, node: &NewExpression) -> Result<()> {
self.end_visit_node(node)
}
fn visit_mapping(&mut self, node: &Mapping) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_mapping(&mut self, node: &Mapping) -> Result<()> {
self.end_visit_node(node)
}
fn visit_modifier_definition(&mut self, node: &ModifierDefinition) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_modifier_definition(&mut self, node: &ModifierDefinition) -> Result<()> {
self.end_visit_node(node)
}
fn visit_modifier_invocation(&mut self, node: &ModifierInvocation) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_modifier_invocation(&mut self, node: &ModifierInvocation) -> Result<()> {
self.end_visit_node(node)
}
fn visit_override_specifier(&mut self, node: &OverrideSpecifier) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_override_specifier(&mut self, node: &OverrideSpecifier) -> Result<()> {
self.end_visit_node(node)
}
fn visit_parameter_list(&mut self, node: &ParameterList) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_parameter_list(&mut self, node: &ParameterList) -> Result<()> {
self.end_visit_node(node)
}
fn visit_pragma_directive(&mut self, node: &PragmaDirective) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_pragma_directive(&mut self, node: &PragmaDirective) -> Result<()> {
self.end_visit_node(node)
}
fn visit_return(&mut self, node: &Return) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_return(&mut self, node: &Return) -> Result<()> {
self.end_visit_node(node)
}
fn visit_revert_statement(&mut self, node: &RevertStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_revert_statement(&mut self, node: &RevertStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_source_unit(&mut self, node: &SourceUnit) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_source_unit(&mut self, node: &SourceUnit) -> Result<()> {
self.end_visit_node(node)
}
fn visit_struct_definition(&mut self, node: &StructDefinition) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_struct_definition(&mut self, node: &StructDefinition) -> Result<()> {
self.end_visit_node(node)
}
fn visit_structured_documentation(&mut self, node: &StructuredDocumentation) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_structured_documentation(&mut self, node: &StructuredDocumentation) -> Result<()> {
self.end_visit_node(node)
}
fn visit_try_statement(&mut self, node: &TryStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_try_statement(&mut self, node: &TryStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_try_catch_clause(&mut self, node: &TryCatchClause) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_try_catch_clause(&mut self, node: &TryCatchClause) -> Result<()> {
self.end_visit_node(node)
}
fn visit_tuple_expression(&mut self, node: &TupleExpression) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_tuple_expression(&mut self, node: &TupleExpression) -> Result<()> {
self.end_visit_node(node)
}
fn visit_unary_operation(&mut self, node: &UnaryOperation) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_unary_operation(&mut self, node: &UnaryOperation) -> Result<()> {
self.end_visit_node(node)
}
fn visit_user_defined_type_name(&mut self, node: &UserDefinedTypeName) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_user_defined_type_name(&mut self, node: &UserDefinedTypeName) -> Result<()> {
self.end_visit_node(node)
}
fn visit_user_defined_value_type_definition(
&mut self,
node: &UserDefinedValueTypeDefinition,
) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_user_defined_value_type_definition(
&mut self,
node: &UserDefinedValueTypeDefinition,
) -> Result<()> {
self.end_visit_node(node)
}
fn visit_using_for_directive(&mut self, node: &UsingForDirective) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_using_for_directive(&mut self, node: &UsingForDirective) -> Result<()> {
self.end_visit_node(node)
}
fn visit_variable_declaration(&mut self, node: &VariableDeclaration) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_variable_declaration(&mut self, node: &VariableDeclaration) -> Result<()> {
self.end_visit_node(node)
}
fn visit_variable_declaration_statement(
&mut self,
node: &VariableDeclarationStatement,
) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_variable_declaration_statement(
&mut self,
node: &VariableDeclarationStatement,
) -> Result<()> {
self.end_visit_node(node)
}
fn visit_while_statement(&mut self, node: &WhileStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_while_statement(&mut self, node: &WhileStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_do_while_statement(&mut self, node: &DoWhileStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_do_visit_while_statement(&mut self, node: &DoWhileStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_continue_statement(&mut self, node: &Continue) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_continue_statement(&mut self, node: &Continue) -> Result<()> {
self.end_visit_node(node)
}
fn visit_placeholder_statement(&mut self, node: &PlaceholderStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_placeholder_statement(&mut self, node: &PlaceholderStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_break_statement(&mut self, node: &Break) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_break_statement(&mut self, node: &Break) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_block(&mut self, node: &YulBlock) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_block(&mut self, node: &YulBlock) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_statement(&mut self, node: &YulStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_statement(&mut self, node: &YulStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_expression(&mut self, node: &YulExpression) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_expression(&mut self, node: &YulExpression) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_literal(&mut self, node: &YulLiteral) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_literal(&mut self, node: &YulLiteral) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_identifier(&mut self, node: &YulIdentifier) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_identifier(&mut self, node: &YulIdentifier) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_function_call(&mut self, node: &YulFunctionCall) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_function_call(&mut self, node: &YulFunctionCall) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_if(&mut self, node: &YulIf) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_if(&mut self, node: &YulIf) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_switch(&mut self, node: &YulSwitch) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_switch(&mut self, node: &YulSwitch) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_case(&mut self, node: &YulCase) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_case(&mut self, node: &YulCase) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_for_loop(&mut self, node: &YulForLoop) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_for_loop(&mut self, node: &YulForLoop) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_assignment(&mut self, node: &YulAssignment) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_assignment(&mut self, node: &YulAssignment) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_variable_declaration(&mut self, node: &YulVariableDeclaration) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_variable_declaration(&mut self, node: &YulVariableDeclaration) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_typed_name(&mut self, node: &YulTypedName) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_typed_name(&mut self, node: &YulTypedName) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_expression_statement(&mut self, node: &YulExpressionStatement) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_expression_statement(&mut self, node: &YulExpressionStatement) -> Result<()> {
self.end_visit_node(node)
}
fn visit_yul_function_definition(&mut self, node: &YulFunctionDefinition) -> Result<bool> {
self.visit_node(node)
}
fn end_visit_yul_function_definition(&mut self, node: &YulFunctionDefinition) -> Result<()> {
self.end_visit_node(node)
}
fn visit_node(&mut self, _node: &impl Node) -> Result<bool> {
Ok(true)
}
fn end_visit_node(&mut self, _node: &impl Node) -> Result<()> {
Ok(())
}
fn visit_immediate_children(
&mut self,
_node_id: NodeID,
_node_children_ids: Vec<NodeID>,
) -> Result<()> {
Ok(())
}
fn visit_node_id(&mut self, _node_id: Option<NodeID>) -> Result<()> {
Ok(())
}
}
pub trait Node {
/// [`Node::accept`] is designed to propagate
fn accept(&self, _visitor: &mut impl ASTConstVisitor) -> Result<()> {
Ok(())
}
/// [`Node::accept_metadata`] is designed to propagate into the AST subtree
/// although it doesn't happen by itself. [`Node::accept`] triggers the propagation
fn accept_metadata(&self, _visitor: &mut impl ASTConstVisitor) -> Result<()> {
Ok(())
}
/// [`Node::accept_id`] is not designed to propagate into the AST subtree
fn accept_id(&self, _visitor: &mut impl ASTConstVisitor) -> Result<()> {
Ok(())
}
}
pub fn list_accept(list: &Vec<impl Node>, visitor: &mut impl ASTConstVisitor) -> Result<()> {
for elem in list {
elem.accept(visitor)?;
}
Ok(())
}
```
--------------------------------------------------------------------------------
/aderyn_core/src/context/router/tests.rs:
--------------------------------------------------------------------------------
```rust
#[cfg(test)]
mod mir_router {
use crate::{
ast::ASTNode,
context::{
browser::ExtractFunctionCalls,
router::{ECDest, Router},
workspace::WorkspaceContext,
},
test_utils::load_solidity_source_unit,
};
// Utility function to help debug router.
#[allow(dead_code)]
pub fn display(router: &Router, context: &WorkspaceContext) {
println!("Internal calls");
println!("==============");
for (base_contract_id, ic) in &router.internal_calls {
let Some(ASTNode::ContractDefinition(c)) = context.nodes.get(base_contract_id) else {
eprintln!("Couldn't resolve contract with ID {}", base_contract_id);
return;
};
println!("Base contract - {}", c.name);
for (start_lookup, lookup) in &ic.routes {
let Some(ASTNode::ContractDefinition(s)) = context.nodes.get(start_lookup) else {
eprintln!("Couldn't resolve contract with ID {}", start_lookup);
return;
};
println!("Start lookup - {}", s.name);
for (func_selectorish, def_id) in lookup {
let Some(ASTNode::FunctionDefinition(f)) = context.nodes.get(def_id) else {
eprintln!("Couldn't resolve contract with ID {}", def_id);
return;
};
println!(
"{} - {} - {:?}",
func_selectorish,
f.name,
context.get_node_sort_key_from_capturable(&f.clone().into())
);
}
}
println!("-------------");
}
}
fn get_ic_router_ctx() -> (Router, WorkspaceContext) {
let context =
load_solidity_source_unit("../tests/contract-playground/src/router/InternalCalls.sol");
(Router::build(&context), context)
}
fn get_mc_router_ctx() -> (Router, WorkspaceContext) {
let context =
load_solidity_source_unit("../tests/contract-playground/src/router/ModifierCalls.sol");
(Router::build(&context), context)
}
fn get_ec_router_ctx() -> (Router, WorkspaceContext) {
let context =
load_solidity_source_unit("../tests/contract-playground/src/router/ExternalCalls.sol");
(Router::build(&context), context)
}
fn get_ec_router_ctx_2() -> (Router, WorkspaceContext) {
let context = load_solidity_source_unit(
"../tests/contract-playground/src/router/FallbackAndReceiveOverrides.sol",
);
(Router::build(&context), context)
}
#[test]
pub fn resolves_internal_calls_3() {
let (router, context) = get_ic_router_ctx();
let basic3_top_contract = context.find_contract_by_name("Basic3Top");
let basic3_right_contract = context.find_contract_by_name("Basic3Right");
let basic3_left_contract = context.find_contract_by_name("Basic3Left");
let basic3_down2_contract = context.find_contract_by_name("Basic3Down2");
let basic2_contract = context.find_contract_by_name("Basic2");
let basic2_child_contract = context.find_contract_by_name("Basic2Child");
let basic3_top_function = basic3_top_contract.find_function_by_name("help");
let basic3_top_live = basic3_top_contract.find_function_by_name("live");
let basic3_left_function = basic3_left_contract.find_function_by_name("help");
let basic2_child_gcall_function = basic2_child_contract.find_function_by_name("gcall");
let basic2_g_function = basic2_contract.find_function_by_name("g");
let basic2_child_g_function = basic2_child_contract.find_function_by_name("g");
let basic3_right_function = basic3_right_contract.find_function_by_name("help");
let basic3_down2_function = basic3_down2_contract.find_function_by_name("help");
let basic3_down2_live = basic3_down2_contract.find_function_by_name("live");
let basic3_top_function_calls = ExtractFunctionCalls::from(basic3_top_function).extracted;
let basic3_right_function_calls =
ExtractFunctionCalls::from(basic3_right_function).extracted;
let basic3_left_function_calls = ExtractFunctionCalls::from(basic3_left_function).extracted;
let basic3_down2_function_calls =
ExtractFunctionCalls::from(basic3_down2_function).extracted;
let basic2_child_gcall_function_calls =
ExtractFunctionCalls::from(basic2_child_gcall_function).extracted;
let a = router
._resolve_internal_call(
&context,
basic3_down2_contract,
&basic3_down2_function_calls[0],
)
.unwrap();
assert_eq!(a.id, basic3_right_function.id);
let b = router
._resolve_internal_call(&context, basic3_down2_contract, &basic3_top_function_calls[0])
.unwrap();
assert_eq!(b.id, basic3_down2_live.id);
let c = router
._resolve_internal_call(
&context,
basic3_down2_contract,
&basic3_down2_function_calls[1],
)
.unwrap();
assert_eq!(c.id, basic3_top_live.id);
let d = router
._resolve_internal_call(
&context,
basic3_down2_contract,
&basic3_down2_function_calls[2],
)
.unwrap();
assert_eq!(d.id, basic3_left_function.id);
let e = router
._resolve_internal_call(
&context,
basic3_down2_contract,
&basic3_right_function_calls[0],
)
.unwrap();
assert_eq!(e.id, basic3_left_function.id);
let f = router
._resolve_internal_call(&context, basic3_down2_contract, &basic3_left_function_calls[0])
.unwrap();
assert_eq!(f.id, basic3_top_function.id);
let g = router
._resolve_internal_call(
&context,
basic3_right_contract,
&basic3_right_function_calls[0],
)
.unwrap();
assert_eq!(g.id, basic3_top_function.id);
assert_eq!(basic2_child_g_function.selectorish(), basic2_g_function.selectorish());
let h = router
._resolve_internal_call(
&context,
basic2_child_contract,
&basic2_child_gcall_function_calls[1],
)
.unwrap();
assert_eq!(h.id, basic2_child_g_function.id);
}
#[test]
pub fn resolves_internal_calls_4() {
let (router, context) = get_ic_router_ctx();
let contract = context.find_contract_by_name("Basic4");
let main = contract.find_function_by_name("main");
let priv_func = contract.find_function_by_name("priv");
let library = context.find_contract_by_name("Basic4Lib");
let lib_help1 = library.find_function_by_name("help1");
let func_calls = ExtractFunctionCalls::from(main).extracted;
// internal calls
assert_eq!(func_calls[0].is_internal_call(), Some(true));
assert_eq!(func_calls[1].is_internal_call(), Some(true));
assert_eq!(func_calls[2].is_internal_call(), Some(true));
assert_eq!(func_calls[3].is_internal_call(), Some(true));
assert_eq!(func_calls[4].is_internal_call(), Some(true));
// external calls
assert_eq!(func_calls[5].is_internal_call(), Some(false));
assert_eq!(func_calls[6].is_internal_call(), Some(false));
assert_eq!(func_calls[7].is_internal_call(), Some(false));
let f0 = router._resolve_internal_call(&context, contract, &func_calls[0]);
let f1 = router._resolve_internal_call(&context, contract, &func_calls[1]);
let f2 = router._resolve_internal_call(&context, contract, &func_calls[2]);
let f3 = router._resolve_internal_call(&context, contract, &func_calls[3]);
let f4 = router._resolve_internal_call(&context, contract, &func_calls[4]);
// Lib calls
assert_eq!(f0.unwrap().id, lib_help1.id);
assert_eq!(f1.unwrap().id, lib_help1.id);
assert_eq!(f2.unwrap().id, lib_help1.id);
assert_eq!(f3.unwrap().id, lib_help1.id);
// Private funcs
assert_eq!(f4.unwrap().id, priv_func.id);
}
#[test]
pub fn resolves_internal_calls_5() {
let (router, context) = get_ic_router_ctx();
let free_func = context.find_free_function_by_name("free");
let basic6_contract = context.find_contract_by_name("Basic6");
let basic6_function = basic6_contract.find_function_by_name("main");
let basic6_function_calls = ExtractFunctionCalls::from(basic6_function).extracted;
let a = router
._resolve_internal_call(&context, basic6_contract, &basic6_function_calls[0])
.unwrap();
assert_eq!(a.id, free_func.id);
let basic7_contract = context.find_contract_by_name("Basic7");
let basic7_function = basic7_contract.find_function_by_name("main");
let basic7_function_calls = ExtractFunctionCalls::from(basic7_function).extracted;
let b = router
._resolve_internal_call(&context, basic7_contract, &basic7_function_calls[0])
.unwrap();
assert_eq!(b.id, free_func.id);
let basic8_contract = context.find_contract_by_name("Basic8");
let basic8_function = basic8_contract.find_function_by_name("main");
let basic8_free = basic8_contract.find_function_by_name("free");
let basic8_function_calls = ExtractFunctionCalls::from(basic8_function).extracted;
let c = router
._resolve_internal_call(&context, basic8_contract, &basic8_function_calls[0])
.unwrap();
assert_eq!(c.id, basic8_free.id);
let basic9_contract = context.find_contract_by_name("Basic9");
let basic9_function = basic9_contract.find_function_by_name("help");
let basic9_function_calls = ExtractFunctionCalls::from(basic9_function).extracted;
let d = router
._resolve_internal_call(&context, basic9_contract, &basic9_function_calls[0])
.unwrap();
assert_eq!(d.id, basic8_free.id);
}
#[test]
pub fn resolve_modifier_calls_1() {
let (router, context) = get_mc_router_ctx();
let a_contract = context.find_contract_by_name("A");
let b_contract = context.find_contract_by_name("B");
let c_contract = context.find_contract_by_name("C");
let d_library = context.find_contract_by_name("D");
let a_func = a_contract.find_function_by_name("geez");
let b_func = b_contract.find_function_by_name("tree");
let c_func = c_contract.find_function_by_name("main");
let show_func = d_library.find_function_by_name("show");
let a_modifier_call = &a_func.modifiers[0];
let b_modifier_call = &b_func.modifiers[0];
let c_modifier_call_1 = &c_func.modifiers[0];
let c_modifier_call_2 = &c_func.modifiers[1];
let show_modifier = &show_func.modifiers[0];
let a = router._resolve_modifier_call(&context, b_contract, a_modifier_call).unwrap();
assert_eq!(a.id, b_contract.find_modifier_by_name("modify").id);
let b = router._resolve_modifier_call(&context, c_contract, c_modifier_call_1).unwrap();
assert_eq!(b.id, b_contract.find_modifier_by_name("modify").id);
let c = router._resolve_modifier_call(&context, c_contract, c_modifier_call_2).unwrap();
assert_eq!(c.id, c_contract.find_modifier_by_name("modify").id);
let d = router._resolve_modifier_call(&context, b_contract, b_modifier_call).unwrap();
assert_eq!(d.id, b_contract.find_modifier_by_name("modify").id);
let e = router._resolve_modifier_call(&context, c_contract, show_modifier).unwrap();
assert_eq!(e.id, d_library.find_modifier_by_name("modify").id);
}
#[test]
pub fn resolves_internal_from_library_calls() {
let (router, context) = get_ic_router_ctx();
let basic4_contract = context.find_contract_by_name("Basic4");
let basic4_lib = context.find_contract_by_name("Basic4Lib");
let basic4_aux_lib = context.find_contract_by_name("Basic4AuxLib");
let help1_func = basic4_lib.find_function_by_name("help1");
let ext2_func = basic4_lib.find_function_by_name("ext2");
let aux2 = basic4_aux_lib.find_function_by_name("aux2");
let func_calls = ExtractFunctionCalls::from(help1_func).extracted;
assert!(func_calls[0].is_internal_call().unwrap());
assert!(!func_calls[1].is_internal_call().unwrap());
assert!(func_calls[2].is_internal_call().unwrap());
let a = router._resolve_internal_call(&context, basic4_contract, &func_calls[0]).unwrap();
assert_eq!(a.id, ext2_func.id);
let b = router._resolve_internal_call(&context, basic4_contract, &func_calls[2]).unwrap();
assert_eq!(b.id, aux2.id);
// external calls return none
let c = router._resolve_internal_call(&context, basic4_contract, &func_calls[1]);
assert!(c.is_none());
}
#[test]
pub fn resolve_ext_calls_1() {
let (router, context) = get_ec_router_ctx();
let test_contract = context.find_contract_by_name("TestA");
let test_func = test_contract.find_function_by_name("test");
let func_calls = ExtractFunctionCalls::from(test_func).extracted;
assert_eq!(func_calls[0].is_internal_call(), Some(false));
let b_contract = context.find_contract_by_name("B");
let out = router._resolve_external_call(&context, b_contract, &func_calls[0]).unwrap();
assert!(matches!(out, ECDest::PseudoExtFn(_)));
let e_contract = context.find_contract_by_name("E");
let e_func = e_contract.find_function_by_name("abc");
let out = router._resolve_external_call(&context, e_contract, &func_calls[0]).unwrap();
assert_eq!(out, ECDest::RealExtFn(e_func.id));
let f_contract = context.find_contract_by_name("F");
let f_func = f_contract.find_function_by_name("abc");
let out = router._resolve_external_call(&context, f_contract, &func_calls[0]).unwrap();
assert_eq!(out, ECDest::PublicFn(f_func.id));
let y_contract = context.find_contract_by_name("Y");
let out = router._resolve_external_call(&context, y_contract, &func_calls[0]).unwrap();
assert_eq!(out, ECDest::PublicFn(f_func.id));
}
#[test]
pub fn resolve_ext_calls_2() {
let (router, context) = get_ec_router_ctx();
let test_contract = context.find_contract_by_name("TestD");
let test_func = test_contract.find_function_by_name("test");
let func_calls = ExtractFunctionCalls::from(test_func).extracted;
assert_eq!(func_calls[0].is_internal_call(), Some(false));
let d_contract = context.find_contract_by_name("D");
let out = router._resolve_external_call(&context, d_contract, &func_calls[0]).unwrap();
assert!(matches!(out, ECDest::PseudoExtFn(_)));
}
#[test]
pub fn resolve_ext_calls_3() {
let (router, context) = get_ec_router_ctx_2();
let test_contract = context.find_contract_by_name("TestIt");
let test_func = test_contract.find_function_by_name("test");
let func_calls = ExtractFunctionCalls::from(test_func).extracted;
assert_eq!(func_calls[0].is_internal_call(), Some(false));
let a_contract = context.find_contract_by_name("A");
let b_contract = context.find_contract_by_name("B");
let c_contract = context.find_contract_by_name("C");
let a_fallback = a_contract.find_fallback_function();
let b_fallback = b_contract.find_fallback_function();
// resolve fallback functions
let out = router._resolve_external_call(&context, a_contract, &func_calls[0]).unwrap();
assert_eq!(out, ECDest::Fallback(a_fallback.id));
let out = router._resolve_external_call(&context, b_contract, &func_calls[0]).unwrap();
assert_eq!(out, ECDest::Fallback(b_fallback.id));
let out = router._resolve_external_call(&context, c_contract, &func_calls[0]).unwrap();
assert_eq!(out, ECDest::Fallback(a_fallback.id));
}
#[test]
pub fn resolve_ext_calls_4() {
let (router, context) = get_ec_router_ctx_2();
let a_contract = context.find_contract_by_name("A");
let b_contract = context.find_contract_by_name("B");
let c_contract = context.find_contract_by_name("C");
let a_fallback = a_contract.find_fallback_function();
let a_receive = a_contract.find_receive_function();
let b_fallback = b_contract.find_fallback_function();
// resolve fallback functions
let out = router._resolve_fallback_function(&context, a_contract).unwrap();
assert_eq!(out.id, a_fallback.id);
let out = router._resolve_fallback_function(&context, b_contract).unwrap();
assert_eq!(out.id, b_fallback.id);
let out = router._resolve_fallback_function(&context, c_contract).unwrap();
assert_eq!(out.id, a_fallback.id);
// resolve receive
let out = router._resolve_receive_function(&context, a_contract).unwrap();
assert_eq!(out.id, a_receive.id);
let out = router._resolve_receive_function(&context, b_contract).unwrap();
assert_eq!(out.id, a_receive.id);
let out = router._resolve_receive_function(&context, c_contract).unwrap();
assert_eq!(out.id, a_receive.id);
}
#[test]
pub fn resolve_ext_calls_5() {
let (_, context) = get_ec_router_ctx_2();
let a_contract = context.find_contract_by_name("A");
let b_contract = context.find_contract_by_name("B");
let c_contract = context.find_contract_by_name("C");
let a_funcs = context.entrypoint_functions(a_contract).unwrap();
let b_funcs = context.entrypoint_functions(b_contract).unwrap();
let c_funcs = context.entrypoint_functions(c_contract).unwrap();
assert_eq!(a_funcs.len(), 2);
assert_eq!(b_funcs.len(), 2);
assert_eq!(c_funcs.len(), 2);
}
#[test]
pub fn resolve_ext_calls_6() {
let (_, context) = get_ec_router_ctx();
let b_contract = context.find_contract_by_name("B");
let e_contract = context.find_contract_by_name("E");
let f_contract = context.find_contract_by_name("F");
let y_contract = context.find_contract_by_name("Y");
let d_contract = context.find_contract_by_name("D");
let b_funcs = context.entrypoint_functions(b_contract).unwrap();
let e_funcs = context.entrypoint_functions(e_contract).unwrap();
let f_funcs = context.entrypoint_functions(f_contract).unwrap();
let y_funcs = context.entrypoint_functions(y_contract).unwrap();
let d_funcs = context.entrypoint_functions(d_contract).unwrap();
assert_eq!(b_funcs.len(), 0);
assert_eq!(e_funcs.len(), 1);
assert_eq!(f_funcs.len(), 1);
assert_eq!(y_funcs.len(), 1);
assert_eq!(d_funcs.len(), 0);
}
}
```
--------------------------------------------------------------------------------
/reports/sablier-aderyn-toml-nested-root.md:
--------------------------------------------------------------------------------
```markdown
# Aderyn Analysis Report
This report was generated by [Aderyn](https://github.com/Cyfrin/aderyn), a static analysis tool built by [Cyfrin](https://cyfrin.io), a blockchain security company. This report is not a substitute for manual audit or security review. It should not be relied upon for any purpose other than to assist in the identification of potential security vulnerabilities.
# Table of Contents
- [Summary](#summary)
- [Files Summary](#files-summary)
- [Files Details](#files-details)
- [Issue Summary](#issue-summary)
- [Low Issues](#low-issues)
- [L-1: Unspecific Solidity Pragma](#l-1-unspecific-solidity-pragma)
- [L-2: Address State Variable Set Without Checks](#l-2-address-state-variable-set-without-checks)
- [L-3: Literal Instead of Constant](#l-3-literal-instead-of-constant)
- [L-4: PUSH0 Opcode](#l-4-push0-opcode)
- [L-5: Large Numeric Literal](#l-5-large-numeric-literal)
- [L-6: Internal Function Used Only Once](#l-6-internal-function-used-only-once)
- [L-7: Loop Contains `require`/`revert`](#l-7-loop-contains-requirerevert)
- [L-8: Costly operations inside loop](#l-8-costly-operations-inside-loop)
- [L-9: Unchecked Return](#l-9-unchecked-return)
# Summary
## Files Summary
| Key | Value |
| --- | --- |
| .sol Files | 20 |
| Total nSLOC | 2190 |
## Files Details
| Filepath | nSLOC |
| --- | --- |
| src/SablierV2LockupDynamic.sol | 211 |
| src/SablierV2LockupLinear.sol | 168 |
| src/SablierV2LockupTranched.sol | 161 |
| src/SablierV2NFTDescriptor.sol | 269 |
| src/abstracts/Adminable.sol | 16 |
| src/abstracts/NoDelegateCall.sol | 17 |
| src/abstracts/SablierV2Lockup.sol | 391 |
| src/interfaces/IAdminable.sol | 6 |
| src/interfaces/ISablierV2Lockup.sol | 56 |
| src/interfaces/ISablierV2LockupDynamic.sol | 29 |
| src/interfaces/ISablierV2LockupLinear.sol | 27 |
| src/interfaces/ISablierV2LockupTranched.sol | 29 |
| src/interfaces/ISablierV2NFTDescriptor.sol | 5 |
| src/interfaces/hooks/ISablierV2Recipient.sol | 12 |
| src/interfaces/hooks/ISablierV2Sender.sol | 4 |
| src/libraries/Errors.sol | 50 |
| src/libraries/Helpers.sol | 212 |
| src/libraries/NFTSVG.sol | 144 |
| src/libraries/SVGElements.sol | 200 |
| src/types/DataTypes.sol | 183 |
| **Total** | **2190** |
## Issue Summary
| Category | No. of Issues |
| --- | --- |
| High | 0 |
| Low | 9 |
# Low Issues
## L-1: Unspecific Solidity Pragma
Consider using a specific version of Solidity in your contracts instead of a wide version. For example, instead of `pragma solidity ^0.8.0;`, use `pragma solidity 0.8.0;`
<details><summary>15 Found Instances</summary>
- Found in src/SablierV2LockupDynamic.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupDynamic.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/SablierV2LockupLinear.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupLinear.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/SablierV2LockupTranched.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupTranched.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 3](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L3)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/abstracts/Adminable.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/Adminable.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/abstracts/NoDelegateCall.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/NoDelegateCall.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/abstracts/SablierV2Lockup.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/IAdminable.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/IAdminable.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/ISablierV2Lockup.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2Lockup.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/ISablierV2LockupDynamic.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/ISablierV2LockupLinear.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/ISablierV2LockupTranched.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupTranched.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/ISablierV2NFTDescriptor.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2NFTDescriptor.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/hooks/ISablierV2Recipient.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/hooks/ISablierV2Recipient.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/hooks/ISablierV2Sender.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/hooks/ISablierV2Sender.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
</details>
## L-2: Address State Variable Set Without Checks
Check for `address(0)` when assigning values to address state variables.
<details><summary>4 Found Instances</summary>
- Found in src/abstracts/Adminable.sol [Line: 36](../tests/2024-05-Sablier/v2-core/src/abstracts/Adminable.sol#L36)
```solidity
admin = newAdmin;
```
- Found in src/abstracts/SablierV2Lockup.sol [Line: 55](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L55)
```solidity
admin = initialAdmin;
```
- Found in src/abstracts/SablierV2Lockup.sol [Line: 56](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L56)
```solidity
nftDescriptor = initialNFTDescriptor;
```
- Found in src/abstracts/SablierV2Lockup.sol [Line: 318](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L318)
```solidity
nftDescriptor = newNFTDescriptor;
```
</details>
## L-3: Literal Instead of Constant
Define and use `constant` variables instead of using literals. If the same constant literal value is used multiple times, create a constant state variable and reference it throughout the contract.
<details><summary>12 Found Instances</summary>
- Found in src/SablierV2NFTDescriptor.sol [Line: 140](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L140)
```solidity
truncatedAmount = decimals == 0 ? amount : amount / 10 ** decimals;
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 156](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L156)
```solidity
while (truncatedAmount >= 1000) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 157](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L157)
```solidity
fractionalAmount = (truncatedAmount / 10) % 100; // keep the first two digits after the decimal point
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 158](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L158)
```solidity
truncatedAmount /= 1000;
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 223](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L223)
```solidity
uint256 saturation = ((bitField >> 8) & 0xFF) % 80 + 20;
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 228](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L228)
```solidity
uint256 lightness = (bitField & 0xFF) % 70 + 30;
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 346](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L346)
```solidity
if (bytes(symbol).length > 30) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 361](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L361)
```solidity
else if (fractionalAmount < 10) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 374](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L374)
```solidity
string memory fractionalPart = stringifyFractionalAmount(percentage % 100);
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 377](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L377)
```solidity
string memory wholePart = (percentage / 100).toString();
```
</details>
## L-4: PUSH0 Opcode
Solc compiler version 0.8.20 switches the default target EVM version to Shanghai, which means that the generated bytecode will include PUSH0 opcodes. Be sure to select the appropriate EVM version in case you intend to deploy on a chain other than mainnet like L2 chains that may not support PUSH0, otherwise deployment of your contracts will fail.
<details><summary>20 Found Instances</summary>
- Found in src/SablierV2LockupDynamic.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupDynamic.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/SablierV2LockupLinear.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupLinear.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/SablierV2LockupTranched.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupTranched.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 3](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L3)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/abstracts/Adminable.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/Adminable.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/abstracts/NoDelegateCall.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/NoDelegateCall.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/abstracts/SablierV2Lockup.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/IAdminable.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/IAdminable.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/ISablierV2Lockup.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2Lockup.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/ISablierV2LockupDynamic.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/ISablierV2LockupLinear.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/ISablierV2LockupTranched.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupTranched.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/ISablierV2NFTDescriptor.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2NFTDescriptor.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/hooks/ISablierV2Recipient.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/hooks/ISablierV2Recipient.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/interfaces/hooks/ISablierV2Sender.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/hooks/ISablierV2Sender.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/libraries/Errors.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/libraries/Errors.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/libraries/Helpers.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/libraries/Helpers.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/libraries/NFTSVG.sol [Line: 3](../tests/2024-05-Sablier/v2-core/src/libraries/NFTSVG.sol#L3)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/libraries/SVGElements.sol [Line: 3](../tests/2024-05-Sablier/v2-core/src/libraries/SVGElements.sol#L3)
```solidity
pragma solidity >=0.8.22;
```
- Found in src/types/DataTypes.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/types/DataTypes.sol#L2)
```solidity
pragma solidity >=0.8.22;
```
</details>
## L-5: Large Numeric Literal
Large literal values multiples of 10000 can be replaced with scientific notation.Use `e` notation, for example: `1e18`, instead of its full numeric value.
<details><summary>2 Found Instances</summary>
- Found in src/SablierV2NFTDescriptor.sol [Line: 200](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L200)
```solidity
return streamedAmount * 10_000 / depositedAmount;
```
- Found in src/libraries/SVGElements.sol [Line: 217](../tests/2024-05-Sablier/v2-core/src/libraries/SVGElements.sol#L217)
```solidity
(10_000 - progressNumerical).toString(),
```
</details>
## L-6: Internal Function Used Only Once
Instead of separating the logic into a separate function, consider inlining the logic into the calling function. This can reduce the number of function calls and improve readability.
<details><summary>17 Found Instances</summary>
- Found in src/SablierV2NFTDescriptor.sol [Line: 133](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L133)
```solidity
function abbreviateAmount(uint256 amount, uint256 decimals) internal pure returns (string memory) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 171](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L171)
```solidity
function calculateDurationInDays(uint256 startTime, uint256 endTime) internal pure returns (string memory) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 190](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L190)
```solidity
function calculateStreamedPercentage(
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 206](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L206)
```solidity
function generateAccentColor(address sablier, uint256 streamId) internal view returns (string memory) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 240](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L240)
```solidity
function generateAttributes(
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 261](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L261)
```solidity
function generateDescription(
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 301](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L301)
```solidity
function generateName(string memory sablierModel, string memory streamId) internal pure returns (string memory) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 307](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L307)
```solidity
function mapSymbol(IERC721Metadata sablier) internal view returns (string memory) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 322](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L322)
```solidity
function safeAssetDecimals(address asset) internal view returns (uint8) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 334](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L334)
```solidity
function safeAssetSymbol(address asset) internal view returns (string memory) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 372](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L372)
```solidity
function stringifyPercentage(uint256 percentage) internal pure returns (string memory) {
```
- Found in src/SablierV2NFTDescriptor.sol [Line: 384](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L384)
```solidity
function stringifyStatus(Lockup.Status status) internal pure returns (string memory) {
```
- Found in src/libraries/NFTSVG.sol [Line: 98](../tests/2024-05-Sablier/v2-core/src/libraries/NFTSVG.sol#L98)
```solidity
function generateDefs(
```
- Found in src/libraries/NFTSVG.sol [Line: 120](../tests/2024-05-Sablier/v2-core/src/libraries/NFTSVG.sol#L120)
```solidity
function generateFloatingText(
```
- Found in src/libraries/NFTSVG.sol [Line: 146](../tests/2024-05-Sablier/v2-core/src/libraries/NFTSVG.sol#L146)
```solidity
function generateHrefs(
```
- Found in src/libraries/SVGElements.sol [Line: 78](../tests/2024-05-Sablier/v2-core/src/libraries/SVGElements.sol#L78)
```solidity
function card(
```
- Found in src/libraries/SVGElements.sol [Line: 255](../tests/2024-05-Sablier/v2-core/src/libraries/SVGElements.sol#L255)
```solidity
function stringifyCardType(CardType cardType) internal pure returns (string memory) {
```
</details>
## L-7: Loop Contains `require`/`revert`
Avoid `require` / `revert` statements in a loop because a single bad item can cause the whole transaction to fail. It's better to forgive on fail and return failed elements post processing of the loop
<details><summary>4 Found Instances</summary>
- Found in src/abstracts/SablierV2Lockup.sol [Line: 277](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L277)
```solidity
for (uint256 i = 0; i < count; ++i) {
```
- Found in src/abstracts/SablierV2Lockup.sol [Line: 452](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L452)
```solidity
for (uint256 i = 0; i < streamIdsCount; ++i) {
```
- Found in src/libraries/Helpers.sol [Line: 252](../tests/2024-05-Sablier/v2-core/src/libraries/Helpers.sol#L252)
```solidity
for (uint256 index = 0; index < count; ++index) {
```
- Found in src/libraries/Helpers.sol [Line: 315](../tests/2024-05-Sablier/v2-core/src/libraries/Helpers.sol#L315)
```solidity
for (uint256 index = 0; index < count; ++index) {
```
</details>
## L-8: Costly operations inside loop
Invoking `SSTORE` operations in loops may waste gas. Use a local variable to hold the loop computation result.
<details><summary>4 Found Instances</summary>
- Found in src/SablierV2LockupDynamic.sol [Line: 344](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupDynamic.sol#L344)
```solidity
for (uint256 i = 0; i < segmentCount; ++i) {
```
- Found in src/SablierV2LockupTranched.sol [Line: 248](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupTranched.sol#L248)
```solidity
for (uint256 i = 0; i < trancheCount; ++i) {
```
- Found in src/abstracts/SablierV2Lockup.sol [Line: 277](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L277)
```solidity
for (uint256 i = 0; i < count; ++i) {
```
- Found in src/abstracts/SablierV2Lockup.sol [Line: 452](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L452)
```solidity
for (uint256 i = 0; i < streamIdsCount; ++i) {
```
</details>
## L-9: Unchecked Return
Function returns a value but it is ignored. Consider checking the return value.
<details><summary>1 Found Instances</summary>
- Found in src/abstracts/SablierV2Lockup.sol [Line: 211](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L211)
```solidity
_requireOwned({ tokenId: streamId });
```
</details>
```
--------------------------------------------------------------------------------
/aderyn_core/src/detect/detector.rs:
--------------------------------------------------------------------------------
```rust
use serde::{Deserialize, Serialize};
use strum::{Display, EnumCount, EnumIter, EnumString};
use crate::{
ast::NodeID,
context::workspace::WorkspaceContext,
detect::{high::*, low::*},
};
use std::{
collections::BTreeMap,
error::Error,
fmt::{self, Display},
str::FromStr,
};
pub fn get_all_issue_detectors() -> Vec<Box<dyn IssueDetector>> {
vec![
Box::<DelegatecallInLoopDetector>::default(),
Box::<CentralizationRiskDetector>::default(),
Box::<SolmateSafeTransferLibDetector>::default(),
Box::<AvoidAbiEncodePackedDetector>::default(),
Box::<EcrecoverDetector>::default(),
Box::<DeprecatedOZFunctionDetector>::default(),
Box::<UnsafeERC20OperationDetector>::default(),
Box::<UnspecificSolidityPragmaDetector>::default(),
Box::<StateNoAddressCheckDetector>::default(),
Box::<UnusedPublicFunctionDetector>::default(),
Box::<LiteralsInsteadOfConstantsDetector>::default(),
Box::<EmptyRequireRevertDetector>::default(),
Box::<NonReentrantBeforeOthersDetector>::default(),
Box::<BlockTimestampDeadlineDetector>::default(),
Box::<UnsafeERC721MintDetector>::default(),
Box::<PushZeroOpcodeDetector>::default(),
Box::<ArbitraryTransferFromDetector>::default(),
Box::<ModifierUsedOnlyOnceDetector>::default(),
Box::<EmptyBlockDetector>::default(),
Box::<LargeLiteralValueDetector>::default(),
Box::<InternalFunctionUsedOnceDetector>::default(),
Box::<TodoDetector>::default(),
Box::<InconsistentTypeNamesDetector>::default(),
Box::<UnprotectedInitializerDetector>::default(),
Box::<UnusedErrorDetector>::default(),
Box::<RequireRevertInLoopDetector>::default(),
Box::<DivisionBeforeMultiplicationDetector>::default(),
Box::<UnsafeCastingDetector>::default(),
Box::<EnumerableLoopRemovalDetector>::default(),
Box::<ExperimentalEncoderDetector>::default(),
Box::<IncorrectShiftOrderDetector>::default(),
Box::<StorageArrayMemoryEditDetector>::default(),
Box::<MultipleConstructorsDetector>::default(),
Box::<ReusedContractNameDetector>::default(),
Box::<NestedStructInMappingDetector>::default(),
Box::<SelfdestructDetector>::default(),
Box::<DynamicArrayLengthAssignmentDetector>::default(),
Box::<IncorrectUseOfCaretOperatorDetector>::default(),
Box::<YulReturnDetector>::default(),
Box::<StateVariableShadowingDetector>::default(),
Box::<UncheckedSendDetector>::default(),
Box::<MisusedBooleanDetector>::default(),
Box::<SendEtherNoChecksDetector>::default(),
Box::<DelegateCallUncheckedAddressDetector>::default(),
Box::<TautologicalCompareDetector>::default(),
Box::<RTLODetector>::default(),
Box::<DangerousUnaryOperatorDetector>::default(),
Box::<TautologyOrContraditionDetector>::default(),
Box::<DangerousStrictEqualityOnBalanceDetector>::default(),
Box::<StorageSignedIntegerArrayDetector>::default(),
Box::<RedundantStatementDetector>::default(),
Box::<StateVariableReadExternalDetector>::default(),
Box::<WeakRandomnessDetector>::default(),
Box::<PreDeclaredLocalVariableUsageDetector>::default(),
Box::<DeletionNestedMappingDetector>::default(),
Box::<UnusedStateVariablesDetector>::default(),
Box::<ConstantFunctionContainsAssemblyDetector>::default(),
Box::<BooleanEqualityDetector>::default(),
Box::<TxOriginUsedForAuthDetector>::default(),
Box::<MsgValueUsedInLoopDetector>::default(),
Box::<ContractLocksEtherDetector>::default(),
Box::<LocalVariableShadowingDetector>::default(),
Box::<IncorrectERC721InterfaceDetector>::default(),
Box::<IncorrectERC20InterfaceDetector>::default(),
Box::<UninitializedLocalVariableDetector>::default(),
Box::<ReturnBombDetector>::default(),
Box::<OutOfOrderRetryableDetector>::default(),
Box::<FunctionInitializingStateDetector>::default(),
Box::<DeadCodeDetector>::default(),
Box::<CacheArrayLengthDetector>::default(),
Box::<AssertStateChangeDetector>::default(),
Box::<CostlyLoopDetector>::default(),
Box::<ConstantFunctionChangesStateDetector>::default(),
Box::<BuiltinSymbolShadowingDetector>::default(),
Box::<VoidConstructorDetector>::default(),
Box::<FunctionSelectorCollisionDetector>::default(),
Box::<MissingInheritanceDetector>::default(),
Box::<UnusedImportDetector>::default(),
Box::<UncheckedLowLevelCallDetector>::default(),
Box::<FunctionPointerInConstructorDetector>::default(),
Box::<StateVariableCouldBeConstantDetector>::default(),
Box::<StateVariableChangesWithoutEventDetector>::default(),
Box::<StateVariableCouldBeImmutableDetector>::default(),
Box::<MultiplePlaceholdersDetector>::default(),
Box::<ReentrancyStateChangeDetector>::default(),
Box::<IncorrectUseOfModifierDetector>::default(),
Box::<UncheckedReturnDetector>::default(),
]
}
pub fn get_all_detectors_names() -> Vec<String> {
get_all_issue_detectors().iter().map(|d| d.name()).collect()
}
// Note to maintainers: DO NOT CHANGE THE ORDER OF THESE DERIVE ATTRIBUTES
#[derive(Debug, PartialEq, EnumString, Display)]
#[strum(serialize_all = "kebab-case")]
pub enum IssueDetectorNamePool {
IncorrectUseOfModifier,
ReentrancyStateChange,
StateVariableCouldBeImmutable,
MultiplePlaceholders,
StateChangeWithoutEvent,
MissingInheritance,
UnusedImport,
VoidConstructor,
UncheckedLowLevelCall,
FunctionPointerInConstructor,
DeadCode,
FunctionSelectorCollision,
StorageArrayLengthNotCached,
AssertStateChange,
CostlyLoop,
ConstantFunctionChangesState,
BuiltinSymbolShadowing,
IncorrectERC721Interface,
FunctionInitializingState,
DelegatecallInLoop,
CentralizationRisk,
SolmateSafeTransferLib,
AbiEncodePackedHashCollision,
Ecrecover,
DeprecatedOzFunction,
UnsafeERC20Operation,
UnspecificSolidityPragma,
StateNoAddressCheck,
UnusedPublicFunction,
EmptyRequireRevert,
NonReentrantNotFirst,
BlockTimestampDeadline,
LiteralInsteadOfConstant,
UnsafeOzERC721Mint,
PushZeroOpcode,
ArbitraryTransferFrom,
ModifierUsedOnlyOnce,
UnusedError,
LargeNumericLiteral,
InternalFunctionUsedOnce,
EmptyBlock,
Todo,
InconsistentTypeNames,
UnprotectedInitializer,
RequireRevertInLoop,
DivisionBeforeMultiplication,
UnsafeCasting,
EnumerableLoopRemoval,
ExperimentalEncoder,
IncorrectShiftOrder,
StorageArrayMemoryEdit,
MultipleConstructors,
ReusedContractName,
NestedStructInMapping,
Selfdestruct,
DynamicArrayLengthAssignment,
IncorrectCaretOperator,
YulReturn,
StateVariableShadowing,
UncheckedSend,
MisusedBoolean,
EthSendUncheckedAddress,
DelegateCallUncheckedAddress,
TautologicalCompare,
#[allow(clippy::upper_case_acronyms)]
RTLO,
UncheckedReturn,
DangerousUnaryOperator,
TautologyOrContradiction,
StrictEqualityContractBalance,
SignedIntegerStorageArray,
RedundantStatement,
StateVariableReadExternal,
WeakRandomness,
PreDeclaredLocalVariableUsage,
DeleteNestedMapping,
UnusedStateVariable,
ConstantFunctionContainsAssembly,
BooleanEquality,
TxOriginUsedForAuth,
MsgValueInLoop,
ContractLocksEther,
LocalVariableShadowing,
IncorrectERC20Interface,
UninitializedLocalVariable,
ReturnBomb,
OutOfOrderRetryable,
StateVariableCouldBeConstant,
// NOTE: `Undecided` will be the default name (for new bots).
// If it's accepted, a new variant will be added to this enum before normalizing it in aderyn
Undecided,
}
pub fn request_issue_detector_by_name(detector_name: &str) -> Option<Box<dyn IssueDetector>> {
// Expects a valid detector_name
let detector_name = IssueDetectorNamePool::from_str(detector_name).ok()?;
match detector_name {
IssueDetectorNamePool::ReentrancyStateChange => {
Some(Box::<ReentrancyStateChangeDetector>::default())
}
IssueDetectorNamePool::IncorrectUseOfModifier => {
Some(Box::<IncorrectUseOfModifierDetector>::default())
}
IssueDetectorNamePool::StateVariableCouldBeImmutable => {
Some(Box::<StateVariableCouldBeImmutableDetector>::default())
}
IssueDetectorNamePool::MultiplePlaceholders => {
Some(Box::<MultiplePlaceholdersDetector>::default())
}
IssueDetectorNamePool::StateChangeWithoutEvent => {
Some(Box::<StateVariableChangesWithoutEventDetector>::default())
}
IssueDetectorNamePool::MissingInheritance => {
Some(Box::<MissingInheritanceDetector>::default())
}
IssueDetectorNamePool::LocalVariableShadowing => {
Some(Box::<LocalVariableShadowingDetector>::default())
}
IssueDetectorNamePool::UnusedImport => Some(Box::<UnusedImportDetector>::default()),
IssueDetectorNamePool::VoidConstructor => Some(Box::<VoidConstructorDetector>::default()),
IssueDetectorNamePool::StateVariableCouldBeConstant => {
Some(Box::<StateVariableCouldBeConstantDetector>::default())
}
IssueDetectorNamePool::LiteralInsteadOfConstant => {
Some(Box::<LiteralsInsteadOfConstantsDetector>::default())
}
IssueDetectorNamePool::FunctionPointerInConstructor => {
Some(Box::<FunctionPointerInConstructorDetector>::default())
}
IssueDetectorNamePool::DeadCode => Some(Box::<DeadCodeDetector>::default()),
IssueDetectorNamePool::FunctionSelectorCollision => {
Some(Box::<FunctionSelectorCollisionDetector>::default())
}
IssueDetectorNamePool::StorageArrayLengthNotCached => {
Some(Box::<CacheArrayLengthDetector>::default())
}
IssueDetectorNamePool::AssertStateChange => {
Some(Box::<AssertStateChangeDetector>::default())
}
IssueDetectorNamePool::CostlyLoop => Some(Box::<CostlyLoopDetector>::default()),
IssueDetectorNamePool::ConstantFunctionChangesState => {
Some(Box::<ConstantFunctionChangesStateDetector>::default())
}
IssueDetectorNamePool::BuiltinSymbolShadowing => {
Some(Box::<BuiltinSymbolShadowingDetector>::default())
}
IssueDetectorNamePool::IncorrectERC721Interface => {
Some(Box::<IncorrectERC721InterfaceDetector>::default())
}
IssueDetectorNamePool::OutOfOrderRetryable => {
Some(Box::<OutOfOrderRetryableDetector>::default())
}
IssueDetectorNamePool::FunctionInitializingState => {
Some(Box::<FunctionInitializingStateDetector>::default())
}
IssueDetectorNamePool::IncorrectERC20Interface => {
Some(Box::<IncorrectERC20InterfaceDetector>::default())
}
IssueDetectorNamePool::UninitializedLocalVariable => {
Some(Box::<UninitializedLocalVariableDetector>::default())
}
IssueDetectorNamePool::ReturnBomb => Some(Box::<ReturnBombDetector>::default()),
IssueDetectorNamePool::UnusedStateVariable => {
Some(Box::<UnusedStateVariablesDetector>::default())
}
IssueDetectorNamePool::DelegatecallInLoop => {
Some(Box::<DelegatecallInLoopDetector>::default())
}
IssueDetectorNamePool::CentralizationRisk => {
Some(Box::<CentralizationRiskDetector>::default())
}
IssueDetectorNamePool::SolmateSafeTransferLib => {
Some(Box::<SolmateSafeTransferLibDetector>::default())
}
IssueDetectorNamePool::AbiEncodePackedHashCollision => {
Some(Box::<AvoidAbiEncodePackedDetector>::default())
}
IssueDetectorNamePool::Ecrecover => Some(Box::<EcrecoverDetector>::default()),
IssueDetectorNamePool::DeprecatedOzFunction => {
Some(Box::<DeprecatedOZFunctionDetector>::default())
}
IssueDetectorNamePool::UnsafeERC20Operation => {
Some(Box::<UnsafeERC20OperationDetector>::default())
}
IssueDetectorNamePool::UnspecificSolidityPragma => {
Some(Box::<UnspecificSolidityPragmaDetector>::default())
}
IssueDetectorNamePool::StateNoAddressCheck => {
Some(Box::<StateNoAddressCheckDetector>::default())
}
IssueDetectorNamePool::UnusedPublicFunction => {
Some(Box::<UnusedPublicFunctionDetector>::default())
}
IssueDetectorNamePool::EmptyRequireRevert => {
Some(Box::<EmptyRequireRevertDetector>::default())
}
IssueDetectorNamePool::NonReentrantNotFirst => {
Some(Box::<NonReentrantBeforeOthersDetector>::default())
}
IssueDetectorNamePool::BlockTimestampDeadline => {
Some(Box::<BlockTimestampDeadlineDetector>::default())
}
IssueDetectorNamePool::UnsafeOzERC721Mint => {
Some(Box::<UnsafeERC721MintDetector>::default())
}
IssueDetectorNamePool::PushZeroOpcode => Some(Box::<PushZeroOpcodeDetector>::default()),
IssueDetectorNamePool::ArbitraryTransferFrom => {
Some(Box::<ArbitraryTransferFromDetector>::default())
}
IssueDetectorNamePool::ModifierUsedOnlyOnce => {
Some(Box::<ModifierUsedOnlyOnceDetector>::default())
}
IssueDetectorNamePool::LargeNumericLiteral => {
Some(Box::<LargeLiteralValueDetector>::default())
}
IssueDetectorNamePool::InternalFunctionUsedOnce => {
Some(Box::<InternalFunctionUsedOnceDetector>::default())
}
IssueDetectorNamePool::EmptyBlock => Some(Box::<EmptyBlockDetector>::default()),
IssueDetectorNamePool::Todo => Some(Box::<TodoDetector>::default()),
IssueDetectorNamePool::InconsistentTypeNames => {
Some(Box::<InconsistentTypeNamesDetector>::default())
}
IssueDetectorNamePool::UnprotectedInitializer => {
Some(Box::<UnprotectedInitializerDetector>::default())
}
IssueDetectorNamePool::RequireRevertInLoop => {
Some(Box::<RequireRevertInLoopDetector>::default())
}
IssueDetectorNamePool::UnusedError => Some(Box::<UnusedErrorDetector>::default()),
IssueDetectorNamePool::DivisionBeforeMultiplication => {
Some(Box::<DivisionBeforeMultiplicationDetector>::default())
}
IssueDetectorNamePool::UnsafeCasting => Some(Box::<UnsafeCastingDetector>::default()),
IssueDetectorNamePool::EnumerableLoopRemoval => {
Some(Box::<EnumerableLoopRemovalDetector>::default())
}
IssueDetectorNamePool::ExperimentalEncoder => {
Some(Box::<ExperimentalEncoderDetector>::default())
}
IssueDetectorNamePool::IncorrectShiftOrder => {
Some(Box::<IncorrectShiftOrderDetector>::default())
}
IssueDetectorNamePool::StorageArrayMemoryEdit => {
Some(Box::<StorageArrayMemoryEditDetector>::default())
}
IssueDetectorNamePool::MultipleConstructors => {
Some(Box::<MultipleConstructorsDetector>::default())
}
IssueDetectorNamePool::ReusedContractName => {
Some(Box::<ReusedContractNameDetector>::default())
}
IssueDetectorNamePool::NestedStructInMapping => {
Some(Box::<NestedStructInMappingDetector>::default())
}
IssueDetectorNamePool::Selfdestruct => Some(Box::<SelfdestructDetector>::default()),
IssueDetectorNamePool::DynamicArrayLengthAssignment => {
Some(Box::<DynamicArrayLengthAssignmentDetector>::default())
}
IssueDetectorNamePool::IncorrectCaretOperator => {
Some(Box::<IncorrectUseOfCaretOperatorDetector>::default())
}
IssueDetectorNamePool::YulReturn => Some(Box::<YulReturnDetector>::default()),
IssueDetectorNamePool::StateVariableShadowing => {
Some(Box::<StateVariableShadowingDetector>::default())
}
IssueDetectorNamePool::UncheckedSend => Some(Box::<UncheckedSendDetector>::default()),
IssueDetectorNamePool::MisusedBoolean => Some(Box::<MisusedBooleanDetector>::default()),
IssueDetectorNamePool::EthSendUncheckedAddress => {
Some(Box::<SendEtherNoChecksDetector>::default())
}
IssueDetectorNamePool::DelegateCallUncheckedAddress => {
Some(Box::<DelegateCallUncheckedAddressDetector>::default())
}
IssueDetectorNamePool::TautologicalCompare => {
Some(Box::<TautologicalCompareDetector>::default())
}
IssueDetectorNamePool::RTLO => Some(Box::<RTLODetector>::default()),
IssueDetectorNamePool::UncheckedReturn => Some(Box::<UncheckedReturnDetector>::default()),
IssueDetectorNamePool::DangerousUnaryOperator => {
Some(Box::<DangerousUnaryOperatorDetector>::default())
}
IssueDetectorNamePool::TautologyOrContradiction => {
Some(Box::<TautologyOrContraditionDetector>::default())
}
IssueDetectorNamePool::StrictEqualityContractBalance => {
Some(Box::<DangerousStrictEqualityOnBalanceDetector>::default())
}
IssueDetectorNamePool::SignedIntegerStorageArray => {
Some(Box::<StorageSignedIntegerArrayDetector>::default())
}
IssueDetectorNamePool::RedundantStatement => {
Some(Box::<RedundantStatementDetector>::default())
}
IssueDetectorNamePool::StateVariableReadExternal => {
Some(Box::<StateVariableReadExternalDetector>::default())
}
IssueDetectorNamePool::WeakRandomness => Some(Box::<WeakRandomnessDetector>::default()),
IssueDetectorNamePool::PreDeclaredLocalVariableUsage => {
Some(Box::<PreDeclaredLocalVariableUsageDetector>::default())
}
IssueDetectorNamePool::DeleteNestedMapping => {
Some(Box::<DeletionNestedMappingDetector>::default())
}
IssueDetectorNamePool::ConstantFunctionContainsAssembly => {
Some(Box::<ConstantFunctionContainsAssemblyDetector>::default())
}
IssueDetectorNamePool::BooleanEquality => Some(Box::<BooleanEqualityDetector>::default()),
IssueDetectorNamePool::TxOriginUsedForAuth => {
Some(Box::<TxOriginUsedForAuthDetector>::default())
}
IssueDetectorNamePool::MsgValueInLoop => Some(Box::<MsgValueUsedInLoopDetector>::default()),
IssueDetectorNamePool::ContractLocksEther => {
Some(Box::<ContractLocksEtherDetector>::default())
}
IssueDetectorNamePool::UncheckedLowLevelCall => {
Some(Box::<UncheckedLowLevelCallDetector>::default())
}
IssueDetectorNamePool::Undecided => None,
}
}
pub fn get_issue_detector_by_name(detector_name: &str) -> Box<dyn IssueDetector> {
request_issue_detector_by_name(detector_name).unwrap()
}
#[derive(Debug, PartialEq, Serialize, Deserialize, EnumCount, Clone, EnumIter)]
pub enum IssueSeverity {
Low,
High,
}
impl Display for IssueSeverity {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let issue_description = match self {
IssueSeverity::Low => "Low",
IssueSeverity::High => "High",
};
write!(f, "{}", issue_description).unwrap();
Ok(())
}
}
impl dyn IssueDetector {
pub fn skeletal_clone(&self) -> Box<dyn IssueDetector> {
request_issue_detector_by_name(self.name().as_str()).unwrap()
}
}
pub trait IssueDetector: Send + Sync + 'static {
fn detect(&mut self, _context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
Ok(true)
}
fn severity(&self) -> IssueSeverity {
IssueSeverity::High
}
fn title(&self) -> String {
String::from("Title")
}
fn description(&self) -> String {
String::from("Description")
}
fn name(&self) -> String {
format!("{}", IssueDetectorNamePool::Undecided)
}
// Keys are source file name, line number and source location
// Value is ASTNode NodeID
fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
BTreeMap::new()
}
fn hints(&self) -> BTreeMap<(String, usize, String), String> {
BTreeMap::new()
}
}
```
--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/tautology_or_contradiction.rs:
--------------------------------------------------------------------------------
```rust
use std::{collections::BTreeMap, error::Error};
use crate::ast::{BinaryOperation, NodeID, TypeDescriptions};
use crate::{
capture,
context::workspace::WorkspaceContext,
detect::{
detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
helpers::get_literal_value_or_constant_variable_value,
},
};
use eyre::Result;
use solidity_integer_helper::{
does_operation_make_sense_with_lhs_value, does_operation_make_sense_with_rhs_value,
};
#[derive(Default)]
pub struct TautologyOrContraditionDetector {
// Keys are: [0] source file name, [1] line number, [2] character location of node.
// Do not add items manually, use `capture!` to add nodes to this BTreeMap.
found_instances: BTreeMap<(String, usize, String), NodeID>,
}
impl IssueDetector for TautologyOrContraditionDetector {
fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
for binary_operation in context.binary_operations() {
if let Some(is_tautlogy_or_contradiction) =
binary_operation.is_tautology_or_contradiction(context)
&& is_tautlogy_or_contradiction
{
capture!(self, context, binary_operation);
}
}
Ok(!self.found_instances.is_empty())
}
fn severity(&self) -> IssueSeverity {
IssueSeverity::High
}
fn title(&self) -> String {
String::from("Tautology or Contradiction in comparison")
}
fn description(&self) -> String {
String::from(
"The condition has been determined to be either always true or always false due to the integer range in which we're operating.",
)
}
fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
self.found_instances.clone()
}
fn name(&self) -> String {
IssueDetectorNamePool::TautologyOrContradiction.to_string()
}
}
#[cfg(test)]
mod tautology_or_contradiction_tests {
use crate::detect::{
detector::IssueDetector, high::tautology_or_contradiction::TautologyOrContraditionDetector,
};
#[test]
fn test_tautology_or_contradiction_detector() {
let context = crate::detect::test_utils::load_solidity_source_unit(
"../tests/contract-playground/src/TautologyOrContradiction.sol",
);
let mut detector = TautologyOrContraditionDetector::default();
let found = detector.detect(&context).unwrap();
assert!(found);
assert_eq!(detector.instances().len(), 2);
}
}
pub trait OperationIsTautologyOrContradiction {
fn is_tautology_or_contradiction(&self, context: &WorkspaceContext) -> Option<bool>;
}
impl OperationIsTautologyOrContradiction for BinaryOperation {
fn is_tautology_or_contradiction(&self, context: &WorkspaceContext) -> Option<bool> {
if let (
Some(TypeDescriptions { type_string: Some(lhs_type_string), .. }),
Some(TypeDescriptions { type_string: Some(rhs_type_string), .. }),
operator,
) = (
self.left_expression.as_ref().type_descriptions(),
self.right_expression.as_ref().type_descriptions(),
self.operator.clone(),
) {
let supported_operators = [">", ">=", "<", "<="];
if supported_operators.into_iter().all(|op| op != operator) {
return None;
}
if let Some(lhs_value) = get_literal_value_or_constant_variable_value(
self.left_expression.get_node_id()?,
context,
) && let Some(makes_sense) =
does_operation_make_sense_with_lhs_value(&lhs_value, &operator, rhs_type_string)
&& !makes_sense
{
return Some(true);
}
if let Some(rhs_value) = get_literal_value_or_constant_variable_value(
self.right_expression.get_node_id()?,
context,
) && let Some(makes_sense) =
does_operation_make_sense_with_rhs_value(lhs_type_string, &operator, &rhs_value)
&& !makes_sense
{
return Some(true);
}
}
None
}
}
pub mod solidity_integer_helper {
use num_bigint::BigInt;
use num_traits::One;
use std::{error::Error, ops::Neg};
/// This data type is big enough to handle the extreme values of uint256 and int256
/// (Tests below)
#[derive(PartialEq, Debug, Clone)]
pub struct SolidityNumberRange {
min_val: BigInt,
max_val: BigInt,
}
impl SolidityNumberRange {
fn fully_contains(&self, other_solidity_number_range: &SolidityNumberRange) -> bool {
(self.min_val <= other_solidity_number_range.min_val)
&& (self.max_val >= other_solidity_number_range.max_val)
}
fn fully_excludes(&self, other_solidity_number_range: &SolidityNumberRange) -> bool {
(other_solidity_number_range.max_val < self.min_val)
|| (other_solidity_number_range.min_val > self.max_val)
}
}
/// Does this make sense? (boolean answer)
/// ```no_code
/// if(?uintX, operator, value)
/// ```
///
/// Example (ways to call this function)
///
/// Say x is uint8:
/// Then, when we come across a binary operation like follows:
/// x >= 300
/// we can determine if it makes sense by calling this function
/// does_operation_make_sense_with_rhs_value("uint8", ">=", "300")
///
/// This function checks for the range of integer values of uint8 and returns true if it is
/// neither a tautology nor a contradiction.
///
/// Here, I define tautology as the condition where the range Ex: (>=300) FULLY COVERS the Range
/// of Uint8 Contradiction: When the range Ex:(>=300) fully excludes the Range of Uint8
///
/// Notice how in the above example, the value is on the right hand side.
/// Hence this function is called "does_...rhs_value".
pub fn does_operation_make_sense_with_rhs_value(
type_string: &str,
operator: &str,
value: &str,
) -> Option<bool> {
let allowed_range = get_range_for_type_string(type_string).ok()?;
let allowed_min_val = allowed_range.min_val.clone();
let allowed_max_val = allowed_range.max_val.clone();
let value_as_big_int = BigInt::parse_bytes(value.as_bytes(), 10)?;
// First and foremost if the value is out of range it's 100% either a tautology or a
// contradiction. Hence, return false.
if value_as_big_int < allowed_min_val || value_as_big_int > allowed_max_val {
return Some(false);
}
// At this point, we know that the value we are comparing to, is in the allowed range.
// Now, we can get the represented range, and see if it fully contains the allowed range
// (tatutology) or fully excludes the allowed range (contradiction)
let represented_range = {
match operator {
">=" => Some(SolidityNumberRange {
min_val: value_as_big_int.clone(),
max_val: allowed_max_val.clone(),
}),
">" => Some(SolidityNumberRange {
min_val: value_as_big_int.clone() + BigInt::one(),
max_val: allowed_max_val.clone(),
}),
"<=" => Some(SolidityNumberRange {
min_val: allowed_min_val.clone(),
max_val: value_as_big_int.clone(),
}),
"<" => Some(SolidityNumberRange {
min_val: allowed_min_val.clone(),
max_val: value_as_big_int.clone() - BigInt::one(),
}),
&_ => None,
}
};
if let Some(represented_range) = represented_range {
return Some(
!(represented_range.fully_contains(&allowed_range)
|| represented_range.fully_excludes(&allowed_range)),
);
}
None
}
/// Does this make sense? (boolean answer)
/// ```no_code
/// if(value, operator, uint8?)
/// ```
///
/// Take advantage of the above method by reusing code
///
/// Example (ways to call this function)
///
/// Say x is uint8:
/// Then, when we come across a binary operation like follows:
/// 300 >= x
/// we can determine if it makes sense by calling this function
/// does_operation_make_sense_with_lhs_value("300", ">=", "uint8")
///
/// Notice, here the value 300 is on the left hand side.
pub fn does_operation_make_sense_with_lhs_value(
value: &str,
operator: &str,
type_string: &str,
) -> Option<bool> {
let inverse_operator = {
match operator {
">=" => Some("<="),
"<=" => Some(">="),
">" => Some("<"),
"<" => Some(">"),
_ => None,
}
}?;
does_operation_make_sense_with_rhs_value(type_string, inverse_operator, value)
}
/// Accept the type string to calculate the range.
pub fn get_range_for_type_string(
type_string: &str,
) -> Result<SolidityNumberRange, Box<dyn Error>> {
if type_string.starts_with("uint") {
if let Some((_, num_of_bits)) = &type_string.split_once("uint") {
let num_of_bits = num_of_bits.parse::<u32>()?;
return Ok(SolidityNumberRange {
min_val: find_uint_min(num_of_bits),
max_val: find_uint_max(num_of_bits),
});
}
} else if type_string.starts_with("int")
&& let Some((_, num_of_bits)) = &type_string.split_once("int")
{
let num_of_bits = num_of_bits.parse::<u32>()?;
return Ok(SolidityNumberRange {
min_val: find_int_min(num_of_bits),
max_val: find_int_max(num_of_bits),
});
}
Err("Invalid type string provided!".into())
}
// Helpers to calculate min and max for uint types like uint8, uint16, uint24, and so on . . .
fn find_uint_max(num_of_bits: u32) -> BigInt {
BigInt::parse_bytes(b"2", 10).unwrap().pow(num_of_bits) - BigInt::one()
}
fn find_uint_min(_: u32) -> BigInt {
BigInt::ZERO
}
// Helpers to calculate min and max for int types like int8, int16, int24, and so on . . .
fn find_int_max(num_of_bits: u32) -> BigInt {
BigInt::parse_bytes(b"2", 10).unwrap().pow(num_of_bits - 1) - BigInt::one()
}
fn find_int_min(num_of_bits: u32) -> BigInt {
BigInt::parse_bytes(b"2", 10).unwrap().pow(num_of_bits - 1).neg()
}
#[cfg(test)]
mod test_num_bigint_primitives {
use std::ops::Neg;
use num_bigint::BigInt;
use num_traits::{FromPrimitive, One};
use crate::detect::high::tautology_or_contradiction::solidity_integer_helper::{
does_operation_make_sense_with_rhs_value, find_int_max, find_int_min, find_uint_max,
};
use super::{
SolidityNumberRange, does_operation_make_sense_with_lhs_value,
get_range_for_type_string,
};
/*
Tests to ensure that num_bigint crate holds the capacity to work with numbers
in the range that Solidity language operates in.
*/
#[test]
fn test_2_raised_to_3() {
let two_raised_to_three = BigInt::parse_bytes(b"2", 10).unwrap().pow(3);
assert_eq!(two_raised_to_three, BigInt::from_u8(8).unwrap());
}
#[test]
fn can_find_max_of_uint256() {
// This test shows that we can calculate the biggest possible number in Solidity for
// uint which is 2^256 - 1.
// hence we conclude that because we can represent 2^256 - 1, we can easily cover all
// the smaller variants of uint that is uint8, uint16, .... all the ay upto uint256
// because they are lesser than 2^256 - 1
let uint256_max = BigInt::parse_bytes(b"2", 10).unwrap().pow(256) - BigInt::one();
assert_eq!(
uint256_max,
BigInt::parse_bytes(
b"115792089237316195423570985008687907853269984665640564039457584007913129639935",
10
)
.unwrap()
);
}
#[test]
fn can_find_min_of_int256() {
let int_256_min = BigInt::parse_bytes(b"2", 10).unwrap().pow(255).neg();
assert_eq!(
int_256_min,
BigInt::parse_bytes(
b"-57896044618658097711785492504343953926634992332820282019728792003956564819968",
10
)
.unwrap()
);
}
#[test]
fn can_find_max_of_int256() {
let int_256_max = BigInt::parse_bytes(b"2", 10).unwrap().pow(255) - BigInt::one();
assert_eq!(
int_256_max,
BigInt::parse_bytes(
b"57896044618658097711785492504343953926634992332820282019728792003956564819967",
10
)
.unwrap()
);
}
/*
Tests that our helper methods work which will ensure that min and max value can be calculated
for every bit range from 0 to 256 .
*/
#[test]
fn helper_method_can_find_max_of_uint256() {
let uint256_max = find_uint_max(256);
assert_eq!(
uint256_max,
BigInt::parse_bytes(
b"115792089237316195423570985008687907853269984665640564039457584007913129639935",
10
)
.unwrap()
);
}
#[test]
fn helper_method_can_find_min_of_int256() {
let int_256_min = find_int_min(256);
assert_eq!(
int_256_min,
BigInt::parse_bytes(
b"-57896044618658097711785492504343953926634992332820282019728792003956564819968",
10
)
.unwrap()
);
}
#[test]
fn helper_method_can_find_max_of_int256() {
let int_256_max = find_int_max(256);
assert_eq!(
int_256_max,
BigInt::parse_bytes(
b"57896044618658097711785492504343953926634992332820282019728792003956564819967",
10
)
.unwrap()
);
}
#[test]
fn helper_method_can_find_range_for_int176() {
let actual_range = get_range_for_type_string("int176").unwrap();
let expected_range = SolidityNumberRange {
min_val: BigInt::parse_bytes(
b"-47890485652059026823698344598447161988085597568237568",
10,
)
.unwrap(),
max_val: BigInt::parse_bytes(
b"47890485652059026823698344598447161988085597568237567",
10,
)
.unwrap(),
};
assert_eq!(actual_range, expected_range);
}
#[test]
fn helper_method_can_find_range_for_int248() {
let actual_range = get_range_for_type_string("int248").unwrap();
let expected_range = SolidityNumberRange {
min_val: BigInt::parse_bytes(
b"-226156424291633194186662080095093570025917938800079226639565593765455331328",
10,
)
.unwrap(),
max_val: BigInt::parse_bytes(
b"226156424291633194186662080095093570025917938800079226639565593765455331327",
10,
)
.unwrap(),
};
assert_eq!(actual_range, expected_range);
}
#[test]
fn helper_method_can_find_range_for_int24() {
let actual_range = get_range_for_type_string("int24").unwrap();
let expected_range = SolidityNumberRange {
min_val: BigInt::parse_bytes(b"-8388608", 10).unwrap(),
max_val: BigInt::parse_bytes(b"8388607", 10).unwrap(),
};
assert_eq!(actual_range, expected_range);
}
#[test]
fn helper_method_can_find_range_for_uint144() {
let actual_range = get_range_for_type_string("uint144").unwrap();
let expected_range = SolidityNumberRange {
min_val: BigInt::ZERO,
max_val: BigInt::parse_bytes(b"22300745198530623141535718272648361505980415", 10)
.unwrap(),
};
assert_eq!(actual_range, expected_range);
}
#[test]
fn helper_method_can_find_range_for_uint232() {
let actual_range = get_range_for_type_string("uint232").unwrap();
let expected_range = SolidityNumberRange {
min_val: BigInt::ZERO,
max_val: BigInt::parse_bytes(
b"6901746346790563787434755862277025452451108972170386555162524223799295",
10,
)
.unwrap(),
};
assert_eq!(actual_range, expected_range);
}
#[test]
fn helper_method_can_find_range_for_uint256() {
let actual_range = get_range_for_type_string("uint256").unwrap();
let expected_range = SolidityNumberRange {
min_val: BigInt::ZERO,
max_val: BigInt::parse_bytes(
b"115792089237316195423570985008687907853269984665640564039457584007913129639935",
10,
)
.unwrap(),
};
assert_eq!(actual_range, expected_range);
}
#[test]
fn helper_method_can_find_range_for_uint8() {
let actual_range = get_range_for_type_string("uint8").unwrap();
let expected_range = SolidityNumberRange {
min_val: BigInt::ZERO,
max_val: BigInt::parse_bytes(b"255", 10).unwrap(),
};
assert_eq!(actual_range, expected_range);
}
#[test]
fn does_operation_make_sense_lhs_uint8_part1() {
let does_not_make_sense =
!does_operation_make_sense_with_lhs_value("256", ">=", "uint8").unwrap();
assert!(does_not_make_sense);
}
#[test]
fn does_operation_make_sense_rhs_uint8_part1() {
let does_make_sense =
does_operation_make_sense_with_rhs_value("uint8", "<", "255").unwrap();
assert!(does_make_sense);
}
#[test]
fn does_operation_make_sense_lhs_uint8_part2() {
let does_not_make_sense =
!does_operation_make_sense_with_lhs_value("255", ">=", "uint8").unwrap();
assert!(does_not_make_sense);
}
#[test]
fn does_operation_make_sense_lhs_uint8_part3() {
let does_make_sense =
does_operation_make_sense_with_lhs_value("245", ">=", "uint8").unwrap();
assert!(does_make_sense);
}
#[test]
fn does_operation_make_sense_rhs_uint8_part2() {
let does_make_sense =
does_operation_make_sense_with_rhs_value("uint8", "<", "89").unwrap();
assert!(does_make_sense);
}
#[test]
fn does_operation_make_sense_rhs_uint256_part3() {
let does_make_sense =
does_operation_make_sense_with_rhs_value("uint256", ">", "0").unwrap();
assert!(does_make_sense);
}
#[test]
fn does_operation_make_sense_rhs_uint256_part4() {
let does_not_make_sense =
!does_operation_make_sense_with_rhs_value("uint256", ">=", "0").unwrap();
assert!(does_not_make_sense);
}
#[test]
fn does_operation_make_sense_rhs_uint72_part5() {
let does_not_make_sense =
!does_operation_make_sense_with_rhs_value("uint72", "<", "0").unwrap();
assert!(does_not_make_sense);
}
#[test]
fn does_operation_make_sense_rhs_uint8_part6() {
let does_not_make_sense =
!does_operation_make_sense_with_rhs_value("uint8", ">", "258").unwrap();
assert!(does_not_make_sense);
}
}
}
```
--------------------------------------------------------------------------------
/aderyn_core/src/ast/ast_nodes.rs:
--------------------------------------------------------------------------------
```rust
use super::{
macros::{ast_node, ast_node_no_partial_eq, expr_node, node_group, stmt_node},
*,
};
use std::collections::{BTreeMap, HashMap};
use serde::{Deserialize, Serialize};
node_group! {
SourceUnitNode;
ContractDefinition,
EnumDefinition,
ErrorDefinition,
EventDefinition,
FunctionDefinition,
ImportDirective,
PragmaDirective,
StructDefinition,
UserDefinedValueTypeDefinition,
UsingForDirective,
VariableDeclaration,
}
node_group! {
Expression;
Assignment,
BinaryOperation,
Conditional,
ElementaryTypeNameExpression,
FunctionCall,
FunctionCallOptions,
Identifier,
IndexAccess,
IndexRangeAccess,
Literal,
MemberAccess,
NewExpression,
TupleExpression,
UnaryOperation,
}
node_group! {
Statement;
Block,
Break,
Continue,
DoWhileStatement,
EmitStatement,
ExpressionStatement,
ForStatement,
IfStatement,
InlineAssembly,
PlaceholderStatement,
Return,
RevertStatement,
TryStatement,
UncheckedBlock,
VariableDeclarationStatement,
WhileStatement,
}
node_group! {
ContractDefinitionNode;
EnumDefinition,
ErrorDefinition,
EventDefinition,
FunctionDefinition,
ModifierDefinition,
StructDefinition,
UserDefinedValueTypeDefinition,
UsingForDirective,
VariableDeclaration,
}
#[derive(Clone, Debug, Eq, Serialize, PartialEq, Hash)]
pub enum TypeName {
ArrayTypeName(ArrayTypeName),
ElementaryTypeName(ElementaryTypeName),
FunctionTypeName(FunctionTypeName),
Mapping(Mapping),
/// A string representing the type name.
///
/// This variant applies to older compiler versions.
Raw(String),
UserDefinedTypeName(UserDefinedTypeName),
}
impl<'de> Deserialize<'de> for TypeName {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
let json = serde_json::Value::deserialize(deserializer)?;
let node_type = json.get("nodeType");
if node_type.is_none() {
return Ok(TypeName::Raw(json.to_string()));
}
let type_name = node_type.unwrap().as_str().unwrap();
match type_name {
"FunctionTypeName" => {
Ok(TypeName::FunctionTypeName(serde_json::from_value(json).unwrap()))
}
"ArrayTypeName" => Ok(TypeName::ArrayTypeName(serde_json::from_value(json).unwrap())),
"Mapping" => Ok(TypeName::Mapping(serde_json::from_value(json).unwrap())),
"UserDefinedTypeName" => {
Ok(TypeName::UserDefinedTypeName(serde_json::from_value(json).unwrap()))
}
"ElementaryTypeName" => {
Ok(TypeName::ElementaryTypeName(serde_json::from_value(json).unwrap()))
}
_ => panic!("Unrecognized type name {type_name}"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[serde(tag = "nodeType")]
pub enum UserDefinedTypeNameOrIdentifierPath {
UserDefinedTypeName(UserDefinedTypeName),
IdentifierPath(IdentifierPath),
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[serde(tag = "nodeType")]
pub enum ExpressionOrVariableDeclarationStatement {
ExpressionStatement(ExpressionStatement),
VariableDeclarationStatement(VariableDeclarationStatement),
}
impl ExpressionOrVariableDeclarationStatement {
pub fn get_node_id(&self) -> Option<NodeID> {
match self {
ExpressionOrVariableDeclarationStatement::ExpressionStatement(expression) => {
Some(expression.id)
}
ExpressionOrVariableDeclarationStatement::VariableDeclarationStatement(vd_stmnt) => {
Some(vd_stmnt.id)
}
}
}
}
ast_node!(
#[derive(Hash)]
struct Block {
statements: Vec<Statement>,
}
);
stmt_node!(
#[derive(Hash)]
struct UncheckedBlock {
statements: Vec<Statement>,
}
);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[serde(rename_all = "lowercase")]
pub enum ContractKind {
Contract,
Interface,
Library,
}
ast_node!(
#[derive(Hash)]
struct InheritanceSpecifier {
base_name: UserDefinedTypeNameOrIdentifierPath,
arguments: Option<Vec<Expression>>,
}
);
ast_node!(
#[derive(Hash)]
struct ContractDefinition {
name: String,
name_location: Option<String>,
documentation: Option<Documentation>,
#[serde(rename = "contractKind")]
kind: ContractKind,
#[serde(default, rename = "abstract")]
is_abstract: bool,
base_contracts: Vec<InheritanceSpecifier>,
canonical_name: Option<String>,
contract_dependencies: Vec<NodeID>,
used_errors: Option<Vec<NodeID>>,
used_events: Option<Vec<usize>>,
#[serde(default, rename = "internalFunctionIDs")]
internal_function_ids: BTreeMap<String, usize>,
nodes: Vec<ContractDefinitionNode>,
scope: NodeID,
fully_implemented: bool,
linearized_base_contracts: Vec<NodeID>,
}
);
#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, Hash)]
#[serde(untagged)]
pub enum Documentation {
String(Option<String>),
Structured(Option<StructuredDocumentation>),
}
ast_node!(
#[derive(Hash)]
struct StructuredDocumentation {
text: String,
}
);
ast_node!(
#[derive(Hash)]
struct EnumValue {
name: String,
name_location: Option<String>,
}
);
ast_node!(
#[derive(Hash)]
struct EnumDefinition {
name: String,
name_location: Option<String>,
members: Vec<EnumValue>,
canonical_name: Option<String>,
}
);
ast_node!(
#[derive(Hash)]
struct ErrorDefinition {
documentation: Option<Documentation>,
error_selector: Option<String>,
name: String,
name_location: Option<String>,
parameters: ParameterList,
}
);
ast_node!(
#[derive(Hash)]
struct EventDefinition {
anonymous: bool,
documentation: Option<Documentation>,
name: String,
name_location: Option<String>,
parameters: ParameterList,
event_selector: Option<String>,
}
);
expr_node!(
#[derive(Hash)]
struct UnaryOperation {
operator: String,
/// Whether the unary operator is before or after the expression (e.g. `x++` vs. `++x`)
prefix: bool,
sub_expression: Box<Expression>,
}
);
expr_node!(
#[derive(Hash)]
struct BinaryOperation {
common_type: TypeDescriptions,
left_expression: Box<Expression>,
right_expression: Box<Expression>,
operator: String,
}
);
expr_node!(
#[derive(Hash)]
struct Conditional {
condition: Box<Expression>,
true_expression: Box<Expression>,
false_expression: Box<Expression>,
}
);
expr_node!(
#[derive(Hash)]
struct Assignment {
left_hand_side: Box<Expression>,
right_hand_side: Box<Expression>,
operator: String,
}
);
expr_node!(
#[derive(Hash)]
struct FunctionCall {
kind: FunctionCallKind,
#[serde(default)]
try_call: bool,
names: Vec<String>,
arguments: Vec<Expression>,
expression: Box<Expression>,
}
);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[serde(rename_all = "camelCase")]
pub enum FunctionCallKind {
FunctionCall,
TypeConversion,
StructConstructorCall,
}
expr_node!(
#[derive(Hash)]
struct FunctionCallOptions {
names: Vec<String>,
options: Vec<Expression>,
arguments: Option<Vec<Expression>>,
expression: Box<Expression>,
}
);
expr_node!(
#[derive(Hash)]
struct NewExpression {
type_name: TypeName,
}
);
expr_node!(
#[derive(Hash)]
struct IndexAccess {
base_expression: Box<Expression>,
index_expression: Option<Box<Expression>>,
}
);
expr_node!(
#[derive(Hash)]
struct IndexRangeAccess {
base_expression: Box<Expression>,
start_expression: Option<Box<Expression>>,
end_expression: Option<Box<Expression>>,
}
);
expr_node!(
#[derive(Hash)]
struct MemberAccess {
member_name: String,
expression: Box<Expression>,
referenced_declaration: Option<NodeID>,
}
);
expr_node!(
#[derive(Hash)]
struct ElementaryTypeNameExpression {
type_name: TypeName,
}
);
expr_node!(
#[derive(Hash)]
struct TupleExpression {
components: Vec<Option<Expression>>,
is_inline_array: bool,
}
);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[serde(rename_all = "camelCase")]
pub enum FunctionKind {
Constructor,
Function,
Receive,
Fallback,
FreeFunction,
}
ast_node!(
#[derive(Hash)]
struct ParameterList {
parameters: Vec<VariableDeclaration>,
}
);
ast_node!(
#[derive(Hash)]
struct OverrideSpecifier {
overrides: Vec<UserDefinedTypeNameOrIdentifierPath>,
}
);
ast_node!(
#[derive(Hash)]
struct FunctionDefinition {
base_functions: Option<Vec<NodeID>>,
body: Option<Block>,
documentation: Option<Documentation>,
function_selector: Option<String>,
implemented: bool,
/// The kind of function this node defines. Only valid for Solidity versions 0.5.x and
/// above.
///
/// For cross-version compatibility use [`FunctionDefinition::kind()`].
kind: Option<FunctionKind>,
#[serde(default)]
/// For cross-version compatibility use [`FunctionDefinition::state_mutability()`].
state_mutability: Option<StateMutability>,
#[serde(default, rename = "virtual")]
is_virtual: bool,
/// Whether or not this function is the constructor. Only valid for Solidity versions below
/// 0.5.x.
///
/// After 0.5.x you must use `kind`. For cross-version compatibility use
/// [`FunctionDefinition::kind()`].
#[serde(default)]
is_constructor: bool,
/// Whether or not this function is constant (view or pure). Only valid for Solidity
/// versions below 0.5.x.
///
/// After 0.5.x you must use `state_mutability`. For cross-version compatibility use
/// [`FunctionDefinition::state_mutability()`].
#[serde(default)]
is_declared_const: bool,
/// Whether or not this function is payable. Only valid for Solidity versions below
/// 0.5.x.
///
/// After 0.5.x you must use `state_mutability`. For cross-version compatibility use
/// [`FunctionDefinition::state_mutability()`].
#[serde(default)]
is_payable: bool,
modifiers: Vec<ModifierInvocation>,
name: String,
name_location: Option<String>,
overrides: Option<OverrideSpecifier>,
parameters: ParameterList,
return_parameters: ParameterList,
scope: NodeID,
super_function: Option<NodeID>,
visibility: Visibility,
}
);
ast_node_no_partial_eq!(
struct Identifier {
argument_types: Option<Vec<TypeDescriptions>>,
name: String,
overloaded_declarations: Vec<NodeID>,
referenced_declaration: Option<NodeID>,
type_descriptions: TypeDescriptions,
}
);
ast_node_no_partial_eq!(
struct IdentifierPath {
name: String,
referenced_declaration: i64,
}
);
#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, Hash)]
#[serde(rename_all = "camelCase")]
pub struct SymbolAlias {
pub foreign: Identifier,
pub local: Option<String>,
pub name_location: Option<String>,
}
ast_node!(
#[derive(Hash)]
struct ImportDirective {
file: String,
source_unit: NodeID,
scope: NodeID,
absolute_path: Option<String>,
unit_alias: String,
name_location: Option<String>,
symbol_aliases: Vec<SymbolAlias>,
}
);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[serde(rename_all = "camelCase")]
pub enum LiteralKind {
Bool,
Number,
String,
HexString,
Address,
UnicodeString,
}
expr_node!(
#[derive(Hash)]
struct Literal {
hex_value: String,
value: Option<String>,
subdenomination: Option<String>,
kind: LiteralKind,
}
);
ast_node!(
#[derive(Hash)]
struct ModifierDefinition {
body: Option<Block>,
base_modifiers: Option<Vec<usize>>,
overrides: Option<OverrideSpecifier>,
documentation: Option<Documentation>,
name: String,
name_location: Option<String>,
parameters: ParameterList,
#[serde(default, rename = "virtual")]
is_virtual: bool,
visibility: Visibility,
}
);
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[serde(rename_all = "camelCase")]
pub enum ModifierInvocationKind {
ModifierInvocation,
BaseConstructorSpecifier,
}
ast_node!(
#[derive(Hash)]
struct ModifierInvocation {
arguments: Option<Vec<Expression>>,
modifier_name: IdentifierOrIdentifierPath,
kind: Option<ModifierInvocationKind>,
}
);
#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, Hash)]
#[serde(tag = "nodeType")]
pub enum IdentifierOrIdentifierPath {
Identifier(Identifier),
IdentifierPath(IdentifierPath),
}
ast_node!(
#[derive(Hash)]
struct PragmaDirective {
literals: Vec<String>,
}
);
ast_node!(
struct SourceUnit {
license: Option<String>,
nodes: Vec<SourceUnitNode>,
exported_symbols: Option<HashMap<String, Vec<NodeID>>>,
absolute_path: Option<String>,
#[serde(skip_serializing)]
source: Option<String>,
}
);
stmt_node!(
#[derive(Hash)]
struct ExpressionStatement {
expression: Expression,
}
);
stmt_node!(
#[derive(Hash)]
struct VariableDeclarationStatement {
assignments: Vec<Option<NodeID>>,
declarations: Vec<Option<VariableDeclaration>>,
initial_value: Option<Expression>,
}
);
#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, Hash)]
#[serde(untagged)]
pub enum BlockOrStatement {
Block(Box<Block>),
Statement(Box<Statement>),
}
stmt_node!(
#[derive(Hash)]
struct IfStatement {
condition: Expression,
true_body: BlockOrStatement,
false_body: Option<BlockOrStatement>,
}
);
stmt_node!(
#[derive(Hash)]
struct ForStatement {
initialization_expression: Option<Box<ExpressionOrVariableDeclarationStatement>>,
condition: Option<Expression>,
loop_expression: Option<Box<ExpressionStatement>>,
body: BlockOrStatement,
}
);
stmt_node!(
#[derive(Hash)]
struct DoWhileStatement {
body: Block,
condition: Expression,
}
);
stmt_node!(
#[derive(Hash)]
struct EmitStatement {
event_call: FunctionCall,
}
);
stmt_node!(
#[derive(Hash)]
struct TryStatement {
clauses: Vec<TryCatchClause>,
external_call: FunctionCall,
}
);
stmt_node!(
#[derive(Hash)]
struct RevertStatement {
error_call: FunctionCall,
}
);
ast_node!(
#[derive(Hash)]
struct TryCatchClause {
block: Block,
error_name: String,
parameters: Option<ParameterList>,
}
);
stmt_node!(
#[derive(Hash)]
struct Return {
function_return_parameters: Option<NodeID>, /* When returning in a modifier, this can be
* none */
expression: Option<Expression>,
}
);
ast_node!(
#[derive(Hash)]
struct InlineAssembly {
#[serde(rename = "AST")]
ast: Option<YulBlock>,
evm_version: Option<String>,
external_references: Vec<ExternalReference>,
operations: Option<String>,
}
);
stmt_node!(
#[derive(Hash)]
struct Break {}
);
stmt_node!(
#[derive(Hash)]
struct Continue {}
);
stmt_node!(
#[derive(Hash)]
struct PlaceholderStatement {}
);
stmt_node!(
#[derive(Hash)]
struct WhileStatement {
condition: Expression,
body: BlockOrStatement,
}
);
ast_node!(
#[derive(Hash)]
struct StructDefinition {
name: String,
name_location: Option<String>,
visibility: Visibility,
members: Vec<VariableDeclaration>,
scope: NodeID,
canonical_name: Option<String>,
}
);
#[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, Hash)]
#[serde(rename_all = "camelCase")]
pub struct TypeDescriptions {
pub type_identifier: Option<String>,
pub type_string: Option<String>,
}
ast_node_no_partial_eq!(
struct ElementaryTypeName {
state_mutability: Option<StateMutability>,
name: String,
type_descriptions: TypeDescriptions,
}
);
ast_node_no_partial_eq!(
struct UserDefinedTypeName {
path_node: Option<IdentifierPath>,
referenced_declaration: NodeID,
name: Option<String>,
type_descriptions: TypeDescriptions,
contract_scope: Option<String>,
}
);
ast_node!(
#[derive(Hash)]
struct FunctionTypeName {
visibility: Visibility,
state_mutability: StateMutability,
parameter_types: ParameterList,
return_parameter_types: ParameterList,
type_descriptions: TypeDescriptions,
}
);
ast_node!(
#[derive(Hash)]
struct ArrayTypeName {
base_type: Box<TypeName>,
length: Box<Option<Expression>>,
type_descriptions: TypeDescriptions,
}
);
ast_node!(
#[derive(Hash)]
struct Mapping {
key_type: Box<TypeName>,
value_type: Box<TypeName>,
type_descriptions: TypeDescriptions,
}
);
ast_node!(
#[derive(Hash)]
struct UserDefinedValueTypeDefinition {
underlying_type: TypeName,
name: String,
name_location: Option<String>,
canonical_name: Option<String>,
}
);
ast_node!(
#[derive(Hash)]
struct UsingForDirective {
function_list: Option<Vec<UsingForFunctionItem>>,
#[serde(default)]
global: bool,
library_name: Option<UserDefinedTypeNameOrIdentifierPath>,
type_name: Option<TypeName>,
}
);
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
#[serde(untagged)]
pub enum UsingForFunctionItem {
Function(FunctionIdentifierPath),
OverloadedOperator(OverloadedOperator),
}
/// A wrapper around [IdentifierPath] for the [UsingForDirective].
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct FunctionIdentifierPath {
pub function: IdentifierPath,
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
pub struct OverloadedOperator {
pub definition: IdentifierPath,
pub operator: String,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[serde(rename_all = "lowercase")]
pub enum Mutability {
Immutable,
Mutable,
Constant,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[serde(rename_all = "lowercase")]
pub enum StateMutability {
NonPayable,
Payable,
View,
Pure,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[serde(rename_all = "lowercase")]
pub enum Visibility {
Public,
Private,
Internal,
External,
}
#[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
#[serde(rename_all = "lowercase")]
pub enum StorageLocation {
Default,
Memory,
Calldata,
Storage,
Transient,
}
ast_node!(
#[derive(Hash)]
struct VariableDeclaration {
base_functions: Option<Vec<NodeID>>,
/// Marks whether or not the variable is a constant before Solidity 0.7.x.
///
/// After 0.7.x you must use `mutability`. For cross-version compatibility use
/// [`VariableDeclaration::mutability()`].
#[serde(default)]
constant: bool,
documentation: Option<Documentation>,
function_selector: Option<String>,
indexed: Option<bool>,
/// Marks the variable's mutability from Solidity 0.7.x onwards.
/// For cross-version compatibility use [`VariableDeclaration::mutability()`].
#[serde(default)]
mutability: Option<Mutability>,
name: String,
name_location: Option<String>,
overrides: Option<OverrideSpecifier>,
scope: NodeID,
/// Marks whether or not the variable is a state variable before Solidity 0.7.x.
///
/// After 0.7.x you must use `mutability`. For cross-version compatibility use
/// [`VariableDeclaration::mutability()`].
#[serde(default)]
state_variable: bool,
storage_location: StorageLocation,
type_descriptions: TypeDescriptions,
type_name: Option<TypeName>,
value: Option<Expression>,
visibility: Visibility,
}
);
```