This is page 96 of 103. Use http://codebase.md/cyfrin/aderyn?lines=true&page={x} to view the full context.
# Directory Structure
```
├── .cargo
│ └── config.toml
├── .git-blame-ignore-revs
├── .gitattributes
├── .github
│ ├── images
│ │ ├── aderyn_logo.png
│ │ ├── poweredbycyfrinblack.png
│ │ └── poweredbycyfrinblue.png
│ ├── ISSUE_TEMPLATE
│ │ ├── bug_report.md
│ │ ├── false_positive_issue.md
│ │ └── feature_request.md
│ └── workflows
│ ├── cargo.yml
│ ├── dependencies.yml
│ ├── release.yml
│ ├── reports.yml
│ └── toml.yml
├── .gitignore
├── .gitmodules
├── .vscode
│ └── settings.json
├── aderyn
│ ├── Cargo.toml
│ ├── oranda.json
│ ├── README.md
│ ├── src
│ │ ├── birdsong.rs
│ │ ├── completions.rs
│ │ ├── lib.rs
│ │ ├── lsp.rs
│ │ ├── main.rs
│ │ ├── mcp.rs
│ │ └── panic.rs
│ └── templates
│ └── aderyn.toml
├── aderyn_core
│ ├── .gitignore
│ ├── Cargo.toml
│ ├── README.md
│ ├── src
│ │ ├── ast
│ │ │ ├── ast_nodes.rs
│ │ │ ├── ast.rs
│ │ │ ├── impls
│ │ │ │ ├── ctx
│ │ │ │ │ ├── utils.rs
│ │ │ │ │ └── workspace.rs
│ │ │ │ ├── ctx.rs
│ │ │ │ ├── disp
│ │ │ │ │ ├── blocks.rs
│ │ │ │ │ ├── contracts.rs
│ │ │ │ │ ├── enumerations.rs
│ │ │ │ │ ├── errors.rs
│ │ │ │ │ ├── events.rs
│ │ │ │ │ ├── expressions.rs
│ │ │ │ │ ├── functions.rs
│ │ │ │ │ ├── identifiers.rs
│ │ │ │ │ ├── literals.rs
│ │ │ │ │ ├── modifiers.rs
│ │ │ │ │ ├── statements.rs
│ │ │ │ │ ├── structures.rs
│ │ │ │ │ ├── types.rs
│ │ │ │ │ ├── user_defined_value_types.rs
│ │ │ │ │ ├── using_for_directives.rs
│ │ │ │ │ └── variables.rs
│ │ │ │ ├── disp.rs
│ │ │ │ ├── node
│ │ │ │ │ ├── blocks.rs
│ │ │ │ │ ├── contracts.rs
│ │ │ │ │ ├── documentation.rs
│ │ │ │ │ ├── enumerations.rs
│ │ │ │ │ ├── errors.rs
│ │ │ │ │ ├── events.rs
│ │ │ │ │ ├── expressions.rs
│ │ │ │ │ ├── functions.rs
│ │ │ │ │ ├── identifiers.rs
│ │ │ │ │ ├── import_directives.rs
│ │ │ │ │ ├── literals.rs
│ │ │ │ │ ├── modifiers.rs
│ │ │ │ │ ├── pragma_directives.rs
│ │ │ │ │ ├── source_units.rs
│ │ │ │ │ ├── statements.rs
│ │ │ │ │ ├── structures.rs
│ │ │ │ │ ├── types.rs
│ │ │ │ │ ├── user_defined_value_types.rs
│ │ │ │ │ ├── using_for_directives.rs
│ │ │ │ │ └── variables.rs
│ │ │ │ ├── node.rs
│ │ │ │ ├── own
│ │ │ │ │ ├── hashing.rs
│ │ │ │ │ ├── node_id.rs
│ │ │ │ │ ├── source_units.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ └── own.rs
│ │ │ ├── impls.rs
│ │ │ ├── macros.rs
│ │ │ ├── magic.rs
│ │ │ ├── node_type.rs
│ │ │ └── yul.rs
│ │ ├── ast.rs
│ │ ├── audit
│ │ │ ├── attack_surface.rs
│ │ │ ├── auditor.rs
│ │ │ ├── entrypoint.rs
│ │ │ └── public_functions_no_sender.rs
│ │ ├── audit.rs
│ │ ├── context
│ │ │ ├── browser
│ │ │ │ ├── ancestral_line.rs
│ │ │ │ ├── closest_ancestor.rs
│ │ │ │ ├── external_calls.rs
│ │ │ │ ├── extractor.rs
│ │ │ │ ├── immediate_children.rs
│ │ │ │ ├── location.rs
│ │ │ │ ├── macros.rs
│ │ │ │ ├── parent.rs
│ │ │ │ ├── peek_over.rs
│ │ │ │ ├── peek_under.rs
│ │ │ │ ├── peek.rs
│ │ │ │ ├── siblings.rs
│ │ │ │ ├── sort_nodes.rs
│ │ │ │ └── storage_vars.rs
│ │ │ ├── browser.rs
│ │ │ ├── capturable.rs
│ │ │ ├── flow
│ │ │ │ ├── display.rs
│ │ │ │ ├── error.rs
│ │ │ │ ├── kind.rs
│ │ │ │ ├── primitives.rs
│ │ │ │ ├── reducibles.rs
│ │ │ │ ├── tests.rs
│ │ │ │ ├── utils.rs
│ │ │ │ ├── visualizer.rs
│ │ │ │ └── voids.rs
│ │ │ ├── flow.rs
│ │ │ ├── graph
│ │ │ │ ├── callgraph
│ │ │ │ │ ├── legacy.rs
│ │ │ │ │ ├── new.rs
│ │ │ │ │ ├── tests.rs
│ │ │ │ │ ├── utils.rs
│ │ │ │ │ └── visit.rs
│ │ │ │ ├── callgraph.rs
│ │ │ │ ├── preprocess
│ │ │ │ │ ├── legacy.rs
│ │ │ │ │ └── new.rs
│ │ │ │ ├── preprocess.rs
│ │ │ │ ├── traits.rs
│ │ │ │ └── utils.rs
│ │ │ ├── graph.rs
│ │ │ ├── macros.rs
│ │ │ ├── mcp
│ │ │ │ ├── callgraph
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ ├── callgraph.rs
│ │ │ │ ├── contract_surface
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── util.rs
│ │ │ │ ├── contract_surface.rs
│ │ │ │ ├── list_contracts
│ │ │ │ │ ├── render.rs
│ │ │ │ │ └── tool.rs
│ │ │ │ ├── list_contracts.rs
│ │ │ │ ├── node_finder
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ ├── node_finder.rs
│ │ │ │ ├── node_summarizer
│ │ │ │ │ ├── render.rs
│ │ │ │ │ ├── tool.rs
│ │ │ │ │ └── utils.rs
│ │ │ │ ├── node_summarizer.rs
│ │ │ │ ├── project_overview
│ │ │ │ │ ├── render.rs
│ │ │ │ │ └── tool.rs
│ │ │ │ ├── project_overview.rs
│ │ │ │ ├── tool_guide
│ │ │ │ │ └── tool.rs
│ │ │ │ └── tool_guide.rs
│ │ │ ├── mcp.rs
│ │ │ ├── router
│ │ │ │ ├── external_calls.rs
│ │ │ │ ├── internal_calls.rs
│ │ │ │ ├── modifier_calls.rs
│ │ │ │ └── tests.rs
│ │ │ ├── router.rs
│ │ │ └── workspace.rs
│ │ ├── context.rs
│ │ ├── detect
│ │ │ ├── detector.rs
│ │ │ ├── entrypoint.rs
│ │ │ ├── helpers.rs
│ │ │ ├── high
│ │ │ │ ├── _template.rs
│ │ │ │ ├── abi_encode_packed_hash_collision.rs
│ │ │ │ ├── arbitrary_transfer_from.rs
│ │ │ │ ├── const_func_changes_state.rs
│ │ │ │ ├── contract_locks_ether.rs
│ │ │ │ ├── dangerous_unary_operator.rs
│ │ │ │ ├── delegate_call_unchecked_address.rs
│ │ │ │ ├── delete_nested_mapping.rs
│ │ │ │ ├── dynamic_array_length_assignment.rs
│ │ │ │ ├── enumerable_loop_removal.rs
│ │ │ │ ├── eth_send_unchecked_address.rs
│ │ │ │ ├── experimental_encoder.rs
│ │ │ │ ├── function_selector_collision.rs
│ │ │ │ ├── incorrect_caret_operator.rs
│ │ │ │ ├── incorrect_erc20_interface.rs
│ │ │ │ ├── incorrect_erc721_interface.rs
│ │ │ │ ├── incorrect_shift_order.rs
│ │ │ │ ├── misused_boolean.rs
│ │ │ │ ├── msg_value_in_loops.rs
│ │ │ │ ├── multiple_constructors.rs
│ │ │ │ ├── nested_struct_in_mapping.rs
│ │ │ │ ├── out_of_order_retryable.rs
│ │ │ │ ├── pre_declared_variable_usage.rs
│ │ │ │ ├── reentrancy_state_change.rs
│ │ │ │ ├── reused_contract_name.rs
│ │ │ │ ├── rtlo.rs
│ │ │ │ ├── selfdestruct.rs
│ │ │ │ ├── signed_integer_storage_array.rs
│ │ │ │ ├── state_variable_shadowing.rs
│ │ │ │ ├── storage_array_memory_edit.rs
│ │ │ │ ├── strict_equality_contract_balance.rs
│ │ │ │ ├── tautological_compare.rs
│ │ │ │ ├── tautology_or_contradiction.rs
│ │ │ │ ├── tx_origin_used_for_auth.rs
│ │ │ │ ├── unchecked_low_level_call.rs
│ │ │ │ ├── unchecked_send.rs
│ │ │ │ ├── unprotected_initializer.rs
│ │ │ │ ├── unsafe_casting.rs
│ │ │ │ ├── weak_randomness.rs
│ │ │ │ └── yul_return.rs
│ │ │ ├── high.rs
│ │ │ ├── low
│ │ │ │ ├── _template.rs
│ │ │ │ ├── assert_state_change.rs
│ │ │ │ ├── block_timestamp_deadline.rs
│ │ │ │ ├── boolean_equality.rs
│ │ │ │ ├── builtin_symbol_shadowing.rs
│ │ │ │ ├── centralization_risk.rs
│ │ │ │ ├── constant_function_contains_assembly.rs
│ │ │ │ ├── costly_loop.rs
│ │ │ │ ├── dead_code.rs
│ │ │ │ ├── delegatecall_in_loop.rs
│ │ │ │ ├── deprecated_oz_function.rs
│ │ │ │ ├── division_before_multiplication.rs
│ │ │ │ ├── ecrecover.rs
│ │ │ │ ├── empty_block.rs
│ │ │ │ ├── empty_require_revert.rs
│ │ │ │ ├── function_initializing_state.rs
│ │ │ │ ├── function_pointer_in_constructor.rs
│ │ │ │ ├── inconsistent_type_names.rs
│ │ │ │ ├── incorrect_modifier.rs
│ │ │ │ ├── internal_function_used_once.rs
│ │ │ │ ├── large_numeric_literal.rs
│ │ │ │ ├── literal_instead_of_constant.rs
│ │ │ │ ├── local_variable_shadowing.rs
│ │ │ │ ├── missing_inheritance.rs
│ │ │ │ ├── modifier_used_only_once.rs
│ │ │ │ ├── multiple_placeholders.rs
│ │ │ │ ├── non_reentrant_not_first.rs
│ │ │ │ ├── push_0_opcode.rs
│ │ │ │ ├── redundant_statement.rs
│ │ │ │ ├── require_revert_in_loop.rs
│ │ │ │ ├── return_bomb.rs
│ │ │ │ ├── solmate_safe_transfer_lib.rs
│ │ │ │ ├── state_change_without_event.rs
│ │ │ │ ├── state_no_address_check.rs
│ │ │ │ ├── state_variable_could_be_constant.rs
│ │ │ │ ├── state_variable_could_be_immutable.rs
│ │ │ │ ├── state_variable_read_external.rs
│ │ │ │ ├── storage_array_length_not_cached.rs
│ │ │ │ ├── todo.rs
│ │ │ │ ├── unchecked_return.rs
│ │ │ │ ├── uninitialized_local_variable.rs
│ │ │ │ ├── unsafe_erc20_operation.rs
│ │ │ │ ├── unsafe_oz_erc721_mint.rs
│ │ │ │ ├── unspecific_solidity_pragma.rs
│ │ │ │ ├── unused_error.rs
│ │ │ │ ├── unused_import.rs
│ │ │ │ ├── unused_public_function.rs
│ │ │ │ ├── unused_state_variable.rs
│ │ │ │ └── void_constructor.rs
│ │ │ ├── low.rs
│ │ │ └── test_utils.rs
│ │ ├── detect.rs
│ │ ├── lib.rs
│ │ ├── stats
│ │ │ ├── cloc.rs
│ │ │ ├── dbg_tips.txt
│ │ │ ├── ignore.rs
│ │ │ ├── token.rs
│ │ │ └── util.rs
│ │ ├── stats.rs
│ │ ├── test_utils
│ │ │ └── load_source_unit.rs
│ │ ├── test_utils.rs
│ │ ├── visitor
│ │ │ ├── ast_visitor.rs
│ │ │ ├── macros.rs
│ │ │ └── workspace_visitor.rs
│ │ └── visitor.rs
│ ├── templates
│ │ └── mcp-tool-response
│ │ ├── callgraph.md
│ │ ├── contract_surface.md
│ │ ├── list_contracts.md
│ │ ├── node_finder_get_all.md
│ │ ├── node_finder_grep.md
│ │ ├── node_finder_search.md
│ │ ├── node_summarizer.md
│ │ ├── project_overview.md
│ │ └── tool_guide.md
│ └── tests
│ ├── common
│ │ ├── ancestral_line.rs
│ │ ├── closest_ancestor.rs
│ │ ├── immediate_children.rs
│ │ ├── immediate_parent.rs
│ │ ├── mod.rs
│ │ ├── new_ast_nodes.rs
│ │ ├── peek_over.rs
│ │ └── sibling.rs
│ └── traversal.rs
├── aderyn_driver
│ ├── .gitignore
│ ├── benches
│ │ └── detectors.rs
│ ├── Cargo.toml
│ ├── README.md
│ ├── src
│ │ ├── compile.rs
│ │ ├── config.rs
│ │ ├── display.rs
│ │ ├── driver.rs
│ │ ├── interface
│ │ │ ├── json.rs
│ │ │ ├── lsp.rs
│ │ │ ├── markdown.rs
│ │ │ ├── mod.rs
│ │ │ ├── sarif.rs
│ │ │ ├── tables.rs
│ │ │ └── util.rs
│ │ ├── lib.rs
│ │ ├── mcp.rs
│ │ ├── process.rs
│ │ └── runner.rs
│ └── tests
│ └── astgen.rs
├── bacon.toml
├── benchmarks
│ ├── aderyn
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── iteration_times.svg
│ │ │ └── pdf.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── iteration_times_small.svg
│ │ ├── iteration_times.svg
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── relative_iteration_times_small.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── SD.svg
│ │ └── typical.svg
│ ├── arbitrary-transfer-from
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── avoid-abi-encode-packed
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── block-timestamp-deadline
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── centralization-risk
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── constants-instead-of-literals
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── delegate-call-in-loop
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── deprecated-oz-functions
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── ecrecover
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── empty-block
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── hello_world
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── inconsistent-type-names
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── large-numeric-literal
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── non-reentrant-before-others
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── push-zero-opcode
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── report
│ │ └── index.html
│ ├── require-with-string
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── solmate-safe-transfer-lib
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unindexed-events
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unprotected-initializer
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unsafe-erc20-functions
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unsafe-oz-erc721-mint
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── unspecific-solidity-pragma
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── useless-internal-function
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── useless-modifier
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ ├── useless-public-function
│ │ ├── base
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ ├── change
│ │ │ └── estimates.json
│ │ ├── new
│ │ │ ├── benchmark.json
│ │ │ ├── estimates.json
│ │ │ ├── sample.json
│ │ │ └── tukey.json
│ │ └── report
│ │ ├── both
│ │ │ ├── pdf.svg
│ │ │ └── regression.svg
│ │ ├── change
│ │ │ ├── mean.svg
│ │ │ ├── median.svg
│ │ │ └── t-test.svg
│ │ ├── index.html
│ │ ├── MAD.svg
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ ├── pdf_small.svg
│ │ ├── pdf.svg
│ │ ├── regression_small.svg
│ │ ├── regression.svg
│ │ ├── relative_pdf_small.svg
│ │ ├── relative_regression_small.svg
│ │ ├── SD.svg
│ │ ├── slope.svg
│ │ └── typical.svg
│ └── zero-address-check
│ ├── base
│ │ ├── benchmark.json
│ │ ├── estimates.json
│ │ ├── sample.json
│ │ └── tukey.json
│ ├── change
│ │ └── estimates.json
│ ├── new
│ │ ├── benchmark.json
│ │ ├── estimates.json
│ │ ├── sample.json
│ │ └── tukey.json
│ └── report
│ ├── both
│ │ ├── pdf.svg
│ │ └── regression.svg
│ ├── change
│ │ ├── mean.svg
│ │ ├── median.svg
│ │ └── t-test.svg
│ ├── index.html
│ ├── MAD.svg
│ ├── mean.svg
│ ├── median.svg
│ ├── pdf_small.svg
│ ├── pdf.svg
│ ├── regression_small.svg
│ ├── regression.svg
│ ├── relative_pdf_small.svg
│ ├── relative_regression_small.svg
│ ├── SD.svg
│ ├── slope.svg
│ └── typical.svg
├── Cargo.lock
├── Cargo.toml
├── cli
│ ├── benchmarks.sh
│ └── reportgen.sh
├── CODEOWNERS
├── CONTRIBUTING.md
├── cyfrinup
│ ├── dynamic_script
│ └── why.md
├── deny.toml
├── dist-workspace.toml
├── funding.json
├── LICENSE
├── Makefile
├── package-lock.json
├── package.json
├── README.md
├── RELEASE_CHECKLIST.md
├── reports
│ ├── adhoc-sol-files-highs-only-report.json
│ ├── adhoc-sol-files-report.md
│ ├── ccip-functions-report.md
│ ├── empty_report.md
│ ├── hardhat-playground-report.md
│ ├── nft-report-icm.md
│ ├── nft-report.md
│ ├── prb-math-report.md
│ ├── report.json
│ ├── report.md
│ ├── report.sarif
│ ├── sablier-aderyn-toml-nested-root.md
│ ├── templegold-report.md
│ └── uniswap_profile.md
├── rust-toolchain.toml
├── rustfmt.toml
├── tests
│ ├── adhoc-sol-files
│ │ ├── aderyn.toml
│ │ ├── Counter.sol
│ │ ├── DemoASTNodes.sol
│ │ ├── Helper.sol
│ │ ├── InconsistentUints.sol
│ │ ├── inheritance
│ │ │ ├── ExtendedInheritance.sol
│ │ │ ├── IContractInheritance.sol
│ │ │ └── InheritanceBase.sol
│ │ ├── InternalFunctions.sol
│ │ ├── lib
│ │ │ └── ThisShouldBeExcluded.sol
│ │ ├── multiple-versions
│ │ │ ├── 0.4
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ ├── 0.5
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ ├── 0.6
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ ├── 0.7
│ │ │ │ ├── A.sol
│ │ │ │ └── B.sol
│ │ │ └── 0.8
│ │ │ ├── A.sol
│ │ │ └── B.sol
│ │ ├── OnceModifierExample.sol
│ │ └── StateVariables.sol
│ ├── ast
│ │ ├── abstract_contract.json
│ │ ├── address_payable.json
│ │ ├── array_type_name.json
│ │ ├── ast-erc4626.json
│ │ ├── base_constructor_call.json
│ │ ├── bit_not.json
│ │ ├── call.json
│ │ ├── constructor.json
│ │ ├── contract_dep_order.json
│ │ ├── do_while.json
│ │ ├── documentation_1.json
│ │ ├── documentation_2.json
│ │ ├── documentation_3.json
│ │ ├── documentation_local_variable.json
│ │ ├── documentation_on_statements.json
│ │ ├── documentation_triple.json
│ │ ├── empty_block.json
│ │ ├── enum_value_declaration.json
│ │ ├── enum_value.json
│ │ ├── event_definition.json
│ │ ├── experimental_encoder_pragma.json
│ │ ├── fallback_and_reveice_ether.json
│ │ ├── fallback_payable.json
│ │ ├── fallback.json
│ │ ├── function_type.json
│ │ ├── function.json
│ │ ├── global_enum.json
│ │ ├── global_struct.json
│ │ ├── inheritance_specifier.json
│ │ ├── leave.json
│ │ ├── license.json
│ │ ├── long_type_name_binary_operation.json
│ │ ├── long_type_name_identifier.json
│ │ ├── loop.json
│ │ ├── mappings.json
│ │ ├── modifier_definition.json
│ │ ├── modifier_invocation.json
│ │ ├── mutability.json
│ │ ├── nested_functions.json
│ │ ├── non_utf8.json
│ │ ├── override.json
│ │ ├── placeholder_statement.json
│ │ ├── receive_ether.json
│ │ ├── short_type_name_ref.json
│ │ ├── short_type_name.json
│ │ ├── slot_offset.json
│ │ ├── smoke.json
│ │ ├── source_location.json
│ │ ├── string.json
│ │ ├── stringlit.json
│ │ ├── switch_default.json
│ │ ├── switch.json
│ │ ├── try_catch.json
│ │ ├── two_base_functions.json
│ │ ├── unicode.json
│ │ ├── used_errors.json
│ │ ├── userDefinedValueType.json
│ │ ├── using_for_directive.json
│ │ ├── var_access.json
│ │ └── yul_hex_literal.json
│ ├── contract-playground
│ │ ├── .github
│ │ │ └── workflows
│ │ │ └── test.yml
│ │ ├── .gitignore
│ │ ├── dot
│ │ │ └── .gitkeep
│ │ ├── foundry.toml
│ │ ├── README.md
│ │ ├── script
│ │ │ └── Counter.s.sol
│ │ ├── src
│ │ │ ├── AbstractContract.sol
│ │ │ ├── AderynIgnoreCustomDetectors.sol
│ │ │ ├── AdminContract.sol
│ │ │ ├── ArbitraryTransferFrom.sol
│ │ │ ├── AssemblyExample.sol
│ │ │ ├── AssertStateChange.sol
│ │ │ ├── auditor_mode
│ │ │ │ ├── ExternalCalls.sol
│ │ │ │ └── PublicFunctionsWithoutSenderCheck.sol
│ │ │ ├── BooleanEquality.sol
│ │ │ ├── BuiltinSymbolShadow.sol
│ │ │ ├── CacheArrayLength.sol
│ │ │ ├── CallGraphTests.sol
│ │ │ ├── Casting.sol
│ │ │ ├── cloc
│ │ │ │ ├── AnotherHeavilyCommentedContract.sol
│ │ │ │ ├── EmptyContractFile.sol
│ │ │ │ └── HeavilyCommentedContract.sol
│ │ │ ├── CompilerBugStorageSignedIntegerArray.sol
│ │ │ ├── ConstantFuncsAssembly.sol
│ │ │ ├── ConstantsLiterals.sol
│ │ │ ├── ConstFuncChangeState.sol
│ │ │ ├── ContractLocksEther.sol
│ │ │ ├── ContractWithTodo.sol
│ │ │ ├── control_flow
│ │ │ │ └── SimpleProgram.sol
│ │ │ ├── CostlyOperationsInsideLoops.sol
│ │ │ ├── Counter.sol
│ │ │ ├── CrazyPragma.sol
│ │ │ ├── DangerousStrictEquality1.sol
│ │ │ ├── DangerousStrictEquality2.sol
│ │ │ ├── DangerousUnaryOperator.sol
│ │ │ ├── DeadCode.sol
│ │ │ ├── DelegateCallWithoutAddressCheck.sol
│ │ │ ├── DeletionNestedMappingStructureContract.sol
│ │ │ ├── DeprecatedOZFunctions.sol
│ │ │ ├── DivisionBeforeMultiplication.sol
│ │ │ ├── DynamicArrayLengthAssignment.sol
│ │ │ ├── EmitAfterExternalCall.sol
│ │ │ ├── EmptyBlocks.sol
│ │ │ ├── EnumerableSetIteration.sol
│ │ │ ├── eth2
│ │ │ │ └── DepositContract.sol
│ │ │ ├── ExperimentalEncoder.sol
│ │ │ ├── ExternalCalls.sol
│ │ │ ├── FunctionInitializingState.sol
│ │ │ ├── FunctionPointers.sol
│ │ │ ├── FunctionSignatureCollision.sol
│ │ │ ├── HugeConstants.sol
│ │ │ ├── IgnoreEverything.sol
│ │ │ ├── InconsistentUints.sol
│ │ │ ├── IncorrectCaretOperator.sol
│ │ │ ├── IncorrectERC20.sol
│ │ │ ├── IncorrectERC721.sol
│ │ │ ├── IncorrectModifier.sol
│ │ │ ├── IncorrectShift.sol
│ │ │ ├── inheritance
│ │ │ │ ├── ExtendedInheritance.sol
│ │ │ │ ├── IContractInheritance.sol
│ │ │ │ └── InheritanceBase.sol
│ │ │ ├── InternalFunctions.sol
│ │ │ ├── KeccakContract.sol
│ │ │ ├── LocalVariableShadow.sol
│ │ │ ├── MissingInheritance.sol
│ │ │ ├── MisusedBoolean.sol
│ │ │ ├── MsgValueInLoop.sol
│ │ │ ├── MultipleConstructorSchemes.sol
│ │ │ ├── MultiplePlaceholders.sol
│ │ │ ├── nested
│ │ │ │ ├── 1
│ │ │ │ │ └── Nested.sol
│ │ │ │ └── 2
│ │ │ │ └── Nested.sol
│ │ │ ├── nested_mappings
│ │ │ │ ├── LaterVersion.sol
│ │ │ │ └── NestedMappings.sol
│ │ │ ├── OnceModifierExample.sol
│ │ │ ├── OnlyLibrary.sol
│ │ │ ├── OutOfOrderRetryable.sol
│ │ │ ├── parent_chain
│ │ │ │ └── ParentChainContract.sol
│ │ │ ├── PragmaRange.sol
│ │ │ ├── PreDeclaredVarUsage.sol
│ │ │ ├── PublicFunction.sol
│ │ │ ├── PublicVariableReadInExternalContext.sol
│ │ │ ├── RedundantStatements.sol
│ │ │ ├── ReturnBomb.sol
│ │ │ ├── reused_contract_name
│ │ │ │ ├── ContractA.sol
│ │ │ │ └── ContractB.sol
│ │ │ ├── RevertsAndRequriesInLoops.sol
│ │ │ ├── router
│ │ │ │ ├── ExternalCalls.sol
│ │ │ │ ├── FallbackAndReceiveOverrides.sol
│ │ │ │ ├── InternalCalls.sol
│ │ │ │ ├── ModifierCalls.sol
│ │ │ │ └── VarOverridesFunction.sol
│ │ │ ├── RTLO.sol
│ │ │ ├── SendEtherNoChecks.sol
│ │ │ ├── SendEtherNoChecksLibImport.sol
│ │ │ ├── StateChangeAfterExternalCall.sol
│ │ │ ├── StateShadowing.sol
│ │ │ ├── StateVariableCouldBeDeclaredConstant.sol
│ │ │ ├── StateVariableCouldBeDeclaredImmutable.sol
│ │ │ ├── StateVariables.sol
│ │ │ ├── StateVariablesChangesWithoutEvents.sol
│ │ │ ├── StateVariablesManipulation.sol
│ │ │ ├── StorageConditionals.sol
│ │ │ ├── StorageParameters.sol
│ │ │ ├── T11sTranferer.sol
│ │ │ ├── TautologicalCompare.sol
│ │ │ ├── TautologyOrContradiction.sol
│ │ │ ├── TestERC20.sol
│ │ │ ├── TransientKeyword.sol
│ │ │ ├── Trump.sol
│ │ │ ├── TxOriginUsedForAuth.sol
│ │ │ ├── U2.sol
│ │ │ ├── U3.sol
│ │ │ ├── U4.sol
│ │ │ ├── U5.sol
│ │ │ ├── UncheckedCalls.sol
│ │ │ ├── UncheckedReturn.sol
│ │ │ ├── UncheckedSend.sol
│ │ │ ├── UninitializedLocalVariables.sol
│ │ │ ├── UninitializedStateVariable.sol
│ │ │ ├── uniswap
│ │ │ │ ├── UniswapV2Swapper.sol
│ │ │ │ └── UniswapV3Swapper.sol
│ │ │ ├── UnprotectedInitialize.sol
│ │ │ ├── UnsafeERC721Mint.sol
│ │ │ ├── UnusedError.sol
│ │ │ ├── UnusedImport.sol
│ │ │ ├── UnusedStateVariables.sol
│ │ │ ├── UsingSelfdestruct.sol
│ │ │ ├── VoidConstructor.sol
│ │ │ ├── WeakRandomness.sol
│ │ │ ├── WrongOrderOfLayout.sol
│ │ │ ├── YulReturn.sol
│ │ │ └── ZeroAddressCheck.sol
│ │ └── test
│ │ └── Counter.t.sol
│ ├── foundry-nft-f23
│ │ ├── .github
│ │ │ └── workflows
│ │ │ └── test.yml
│ │ ├── .gitignore
│ │ ├── foundry.lock
│ │ ├── foundry.toml
│ │ ├── README.md
│ │ ├── remappings.txt
│ │ └── src
│ │ ├── BasicNft.sol
│ │ ├── F1.sol
│ │ ├── F2.sol
│ │ ├── Initializer.sol
│ │ └── inner-core-modules
│ │ └── ICM.sol
│ ├── foundry-nft-f23-icm
│ │ ├── .github
│ │ │ └── workflows
│ │ │ └── test.yml
│ │ ├── .gitignore
│ │ ├── aderyn.toml
│ │ ├── foundry.toml
│ │ ├── README.md
│ │ ├── remappings.txt
│ │ └── src
│ │ ├── BasicNft.sol
│ │ ├── F1.sol
│ │ ├── F2.sol
│ │ ├── Initializer.sol
│ │ └── inner-core-modules
│ │ └── ICM.sol
│ ├── hardhat-js-playground
│ │ ├── .gitignore
│ │ ├── artifacts
│ │ │ ├── build-info
│ │ │ │ └── cee6fe9a9a2f03f7ff10a27ab2746af6.json
│ │ │ └── contracts
│ │ │ ├── Counter.sol
│ │ │ │ ├── Counter.dbg.json
│ │ │ │ └── Counter.json
│ │ │ ├── ExtendedInheritance.sol
│ │ │ │ ├── ExtendedInheritance.dbg.json
│ │ │ │ └── ExtendedInheritance.json
│ │ │ ├── IContractInheritance.sol
│ │ │ │ ├── IContractInheritance.dbg.json
│ │ │ │ └── IContractInheritance.json
│ │ │ ├── InheritanceBase.sol
│ │ │ │ ├── InheritanceBase.dbg.json
│ │ │ │ └── InheritanceBase.json
│ │ │ ├── KeccakContract.sol
│ │ │ │ ├── KeccakContract.dbg.json
│ │ │ │ └── KeccakContract.json
│ │ │ ├── Lock.sol
│ │ │ │ ├── Lock.dbg.json
│ │ │ │ └── Lock.json
│ │ │ └── StateVariables.sol
│ │ │ ├── StateVariables.dbg.json
│ │ │ └── StateVariables.json
│ │ ├── contracts
│ │ │ ├── Counter.sol
│ │ │ ├── ExtendedInheritance.sol
│ │ │ ├── IContractInheritance.sol
│ │ │ ├── InheritanceBase.sol
│ │ │ ├── KeccakContract.sol
│ │ │ ├── Lock.sol
│ │ │ └── StateVariables.sol
│ │ ├── hardhat.config.js
│ │ ├── package.json
│ │ ├── README.md
│ │ ├── scripts
│ │ │ └── deploy.js
│ │ ├── test
│ │ │ └── Lock.js
│ │ └── yarn.lock
│ ├── no-sol-files
│ │ ├── extra
│ │ │ └── HelloAgain.md
│ │ ├── Hello.txt
│ │ └── Hello.yul
│ └── toml
│ ├── nested_project1
│ │ ├── aderyn.toml
│ │ ├── folder1
│ │ │ └── hardhat.config.ts
│ │ ├── folder2
│ │ │ └── hardhat.config.ts
│ │ └── folder3
│ │ └── file.txt
│ └── nested_project2
│ ├── aderyn.toml
│ ├── folder1
│ │ └── foundry.toml
│ └── folder2
│ └── file1.txt
├── tools
│ └── xtask
│ ├── Cargo.toml
│ └── src
│ ├── blesspr.rs
│ ├── cut_release.rs
│ ├── flags.rs
│ ├── main.rs
│ ├── reportgen.rs
│ └── tomlgen.rs
└── typos.toml
```
# Files
--------------------------------------------------------------------------------
/reports/sablier-aderyn-toml-nested-root.md:
--------------------------------------------------------------------------------
```markdown
1 | # Aderyn Analysis Report
2 |
3 | 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.
4 | # Table of Contents
5 |
6 | - [Summary](#summary)
7 | - [Files Summary](#files-summary)
8 | - [Files Details](#files-details)
9 | - [Issue Summary](#issue-summary)
10 | - [Low Issues](#low-issues)
11 | - [L-1: Unspecific Solidity Pragma](#l-1-unspecific-solidity-pragma)
12 | - [L-2: Address State Variable Set Without Checks](#l-2-address-state-variable-set-without-checks)
13 | - [L-3: Literal Instead of Constant](#l-3-literal-instead-of-constant)
14 | - [L-4: PUSH0 Opcode](#l-4-push0-opcode)
15 | - [L-5: Large Numeric Literal](#l-5-large-numeric-literal)
16 | - [L-6: Internal Function Used Only Once](#l-6-internal-function-used-only-once)
17 | - [L-7: Loop Contains `require`/`revert`](#l-7-loop-contains-requirerevert)
18 | - [L-8: Costly operations inside loop](#l-8-costly-operations-inside-loop)
19 | - [L-9: Unchecked Return](#l-9-unchecked-return)
20 |
21 |
22 | # Summary
23 |
24 | ## Files Summary
25 |
26 | | Key | Value |
27 | | --- | --- |
28 | | .sol Files | 20 |
29 | | Total nSLOC | 2190 |
30 |
31 |
32 | ## Files Details
33 |
34 | | Filepath | nSLOC |
35 | | --- | --- |
36 | | src/SablierV2LockupDynamic.sol | 211 |
37 | | src/SablierV2LockupLinear.sol | 168 |
38 | | src/SablierV2LockupTranched.sol | 161 |
39 | | src/SablierV2NFTDescriptor.sol | 269 |
40 | | src/abstracts/Adminable.sol | 16 |
41 | | src/abstracts/NoDelegateCall.sol | 17 |
42 | | src/abstracts/SablierV2Lockup.sol | 391 |
43 | | src/interfaces/IAdminable.sol | 6 |
44 | | src/interfaces/ISablierV2Lockup.sol | 56 |
45 | | src/interfaces/ISablierV2LockupDynamic.sol | 29 |
46 | | src/interfaces/ISablierV2LockupLinear.sol | 27 |
47 | | src/interfaces/ISablierV2LockupTranched.sol | 29 |
48 | | src/interfaces/ISablierV2NFTDescriptor.sol | 5 |
49 | | src/interfaces/hooks/ISablierV2Recipient.sol | 12 |
50 | | src/interfaces/hooks/ISablierV2Sender.sol | 4 |
51 | | src/libraries/Errors.sol | 50 |
52 | | src/libraries/Helpers.sol | 212 |
53 | | src/libraries/NFTSVG.sol | 144 |
54 | | src/libraries/SVGElements.sol | 200 |
55 | | src/types/DataTypes.sol | 183 |
56 | | **Total** | **2190** |
57 |
58 |
59 | ## Issue Summary
60 |
61 | | Category | No. of Issues |
62 | | --- | --- |
63 | | High | 0 |
64 | | Low | 9 |
65 |
66 |
67 | # Low Issues
68 |
69 | ## L-1: Unspecific Solidity Pragma
70 |
71 | 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;`
72 |
73 | <details><summary>15 Found Instances</summary>
74 |
75 |
76 | - Found in src/SablierV2LockupDynamic.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupDynamic.sol#L2)
77 |
78 | ```solidity
79 | pragma solidity >=0.8.22;
80 | ```
81 |
82 | - Found in src/SablierV2LockupLinear.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupLinear.sol#L2)
83 |
84 | ```solidity
85 | pragma solidity >=0.8.22;
86 | ```
87 |
88 | - Found in src/SablierV2LockupTranched.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupTranched.sol#L2)
89 |
90 | ```solidity
91 | pragma solidity >=0.8.22;
92 | ```
93 |
94 | - Found in src/SablierV2NFTDescriptor.sol [Line: 3](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L3)
95 |
96 | ```solidity
97 | pragma solidity >=0.8.22;
98 | ```
99 |
100 | - Found in src/abstracts/Adminable.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/Adminable.sol#L2)
101 |
102 | ```solidity
103 | pragma solidity >=0.8.22;
104 | ```
105 |
106 | - Found in src/abstracts/NoDelegateCall.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/NoDelegateCall.sol#L2)
107 |
108 | ```solidity
109 | pragma solidity >=0.8.22;
110 | ```
111 |
112 | - Found in src/abstracts/SablierV2Lockup.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L2)
113 |
114 | ```solidity
115 | pragma solidity >=0.8.22;
116 | ```
117 |
118 | - Found in src/interfaces/IAdminable.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/IAdminable.sol#L2)
119 |
120 | ```solidity
121 | pragma solidity >=0.8.22;
122 | ```
123 |
124 | - Found in src/interfaces/ISablierV2Lockup.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2Lockup.sol#L2)
125 |
126 | ```solidity
127 | pragma solidity >=0.8.22;
128 | ```
129 |
130 | - Found in src/interfaces/ISablierV2LockupDynamic.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol#L2)
131 |
132 | ```solidity
133 | pragma solidity >=0.8.22;
134 | ```
135 |
136 | - Found in src/interfaces/ISablierV2LockupLinear.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol#L2)
137 |
138 | ```solidity
139 | pragma solidity >=0.8.22;
140 | ```
141 |
142 | - Found in src/interfaces/ISablierV2LockupTranched.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupTranched.sol#L2)
143 |
144 | ```solidity
145 | pragma solidity >=0.8.22;
146 | ```
147 |
148 | - Found in src/interfaces/ISablierV2NFTDescriptor.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2NFTDescriptor.sol#L2)
149 |
150 | ```solidity
151 | pragma solidity >=0.8.22;
152 | ```
153 |
154 | - Found in src/interfaces/hooks/ISablierV2Recipient.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/hooks/ISablierV2Recipient.sol#L2)
155 |
156 | ```solidity
157 | pragma solidity >=0.8.22;
158 | ```
159 |
160 | - Found in src/interfaces/hooks/ISablierV2Sender.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/hooks/ISablierV2Sender.sol#L2)
161 |
162 | ```solidity
163 | pragma solidity >=0.8.22;
164 | ```
165 |
166 | </details>
167 |
168 |
169 |
170 | ## L-2: Address State Variable Set Without Checks
171 |
172 | Check for `address(0)` when assigning values to address state variables.
173 |
174 | <details><summary>4 Found Instances</summary>
175 |
176 |
177 | - Found in src/abstracts/Adminable.sol [Line: 36](../tests/2024-05-Sablier/v2-core/src/abstracts/Adminable.sol#L36)
178 |
179 | ```solidity
180 | admin = newAdmin;
181 | ```
182 |
183 | - Found in src/abstracts/SablierV2Lockup.sol [Line: 55](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L55)
184 |
185 | ```solidity
186 | admin = initialAdmin;
187 | ```
188 |
189 | - Found in src/abstracts/SablierV2Lockup.sol [Line: 56](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L56)
190 |
191 | ```solidity
192 | nftDescriptor = initialNFTDescriptor;
193 | ```
194 |
195 | - Found in src/abstracts/SablierV2Lockup.sol [Line: 318](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L318)
196 |
197 | ```solidity
198 | nftDescriptor = newNFTDescriptor;
199 | ```
200 |
201 | </details>
202 |
203 |
204 |
205 | ## L-3: Literal Instead of Constant
206 |
207 | 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.
208 |
209 | <details><summary>12 Found Instances</summary>
210 |
211 |
212 | - Found in src/SablierV2NFTDescriptor.sol [Line: 140](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L140)
213 |
214 | ```solidity
215 | truncatedAmount = decimals == 0 ? amount : amount / 10 ** decimals;
216 | ```
217 |
218 | - Found in src/SablierV2NFTDescriptor.sol [Line: 156](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L156)
219 |
220 | ```solidity
221 | while (truncatedAmount >= 1000) {
222 | ```
223 |
224 | - Found in src/SablierV2NFTDescriptor.sol [Line: 157](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L157)
225 |
226 | ```solidity
227 | fractionalAmount = (truncatedAmount / 10) % 100; // keep the first two digits after the decimal point
228 | ```
229 |
230 | - Found in src/SablierV2NFTDescriptor.sol [Line: 158](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L158)
231 |
232 | ```solidity
233 | truncatedAmount /= 1000;
234 | ```
235 |
236 | - Found in src/SablierV2NFTDescriptor.sol [Line: 223](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L223)
237 |
238 | ```solidity
239 | uint256 saturation = ((bitField >> 8) & 0xFF) % 80 + 20;
240 | ```
241 |
242 | - Found in src/SablierV2NFTDescriptor.sol [Line: 228](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L228)
243 |
244 | ```solidity
245 | uint256 lightness = (bitField & 0xFF) % 70 + 30;
246 | ```
247 |
248 | - Found in src/SablierV2NFTDescriptor.sol [Line: 346](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L346)
249 |
250 | ```solidity
251 | if (bytes(symbol).length > 30) {
252 | ```
253 |
254 | - Found in src/SablierV2NFTDescriptor.sol [Line: 361](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L361)
255 |
256 | ```solidity
257 | else if (fractionalAmount < 10) {
258 | ```
259 |
260 | - Found in src/SablierV2NFTDescriptor.sol [Line: 374](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L374)
261 |
262 | ```solidity
263 | string memory fractionalPart = stringifyFractionalAmount(percentage % 100);
264 | ```
265 |
266 | - Found in src/SablierV2NFTDescriptor.sol [Line: 377](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L377)
267 |
268 | ```solidity
269 | string memory wholePart = (percentage / 100).toString();
270 | ```
271 |
272 | </details>
273 |
274 |
275 |
276 | ## L-4: PUSH0 Opcode
277 |
278 | 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.
279 |
280 | <details><summary>20 Found Instances</summary>
281 |
282 |
283 | - Found in src/SablierV2LockupDynamic.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupDynamic.sol#L2)
284 |
285 | ```solidity
286 | pragma solidity >=0.8.22;
287 | ```
288 |
289 | - Found in src/SablierV2LockupLinear.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupLinear.sol#L2)
290 |
291 | ```solidity
292 | pragma solidity >=0.8.22;
293 | ```
294 |
295 | - Found in src/SablierV2LockupTranched.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupTranched.sol#L2)
296 |
297 | ```solidity
298 | pragma solidity >=0.8.22;
299 | ```
300 |
301 | - Found in src/SablierV2NFTDescriptor.sol [Line: 3](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L3)
302 |
303 | ```solidity
304 | pragma solidity >=0.8.22;
305 | ```
306 |
307 | - Found in src/abstracts/Adminable.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/Adminable.sol#L2)
308 |
309 | ```solidity
310 | pragma solidity >=0.8.22;
311 | ```
312 |
313 | - Found in src/abstracts/NoDelegateCall.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/NoDelegateCall.sol#L2)
314 |
315 | ```solidity
316 | pragma solidity >=0.8.22;
317 | ```
318 |
319 | - Found in src/abstracts/SablierV2Lockup.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L2)
320 |
321 | ```solidity
322 | pragma solidity >=0.8.22;
323 | ```
324 |
325 | - Found in src/interfaces/IAdminable.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/IAdminable.sol#L2)
326 |
327 | ```solidity
328 | pragma solidity >=0.8.22;
329 | ```
330 |
331 | - Found in src/interfaces/ISablierV2Lockup.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2Lockup.sol#L2)
332 |
333 | ```solidity
334 | pragma solidity >=0.8.22;
335 | ```
336 |
337 | - Found in src/interfaces/ISablierV2LockupDynamic.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupDynamic.sol#L2)
338 |
339 | ```solidity
340 | pragma solidity >=0.8.22;
341 | ```
342 |
343 | - Found in src/interfaces/ISablierV2LockupLinear.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupLinear.sol#L2)
344 |
345 | ```solidity
346 | pragma solidity >=0.8.22;
347 | ```
348 |
349 | - Found in src/interfaces/ISablierV2LockupTranched.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2LockupTranched.sol#L2)
350 |
351 | ```solidity
352 | pragma solidity >=0.8.22;
353 | ```
354 |
355 | - Found in src/interfaces/ISablierV2NFTDescriptor.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/ISablierV2NFTDescriptor.sol#L2)
356 |
357 | ```solidity
358 | pragma solidity >=0.8.22;
359 | ```
360 |
361 | - Found in src/interfaces/hooks/ISablierV2Recipient.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/hooks/ISablierV2Recipient.sol#L2)
362 |
363 | ```solidity
364 | pragma solidity >=0.8.22;
365 | ```
366 |
367 | - Found in src/interfaces/hooks/ISablierV2Sender.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/interfaces/hooks/ISablierV2Sender.sol#L2)
368 |
369 | ```solidity
370 | pragma solidity >=0.8.22;
371 | ```
372 |
373 | - Found in src/libraries/Errors.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/libraries/Errors.sol#L2)
374 |
375 | ```solidity
376 | pragma solidity >=0.8.22;
377 | ```
378 |
379 | - Found in src/libraries/Helpers.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/libraries/Helpers.sol#L2)
380 |
381 | ```solidity
382 | pragma solidity >=0.8.22;
383 | ```
384 |
385 | - Found in src/libraries/NFTSVG.sol [Line: 3](../tests/2024-05-Sablier/v2-core/src/libraries/NFTSVG.sol#L3)
386 |
387 | ```solidity
388 | pragma solidity >=0.8.22;
389 | ```
390 |
391 | - Found in src/libraries/SVGElements.sol [Line: 3](../tests/2024-05-Sablier/v2-core/src/libraries/SVGElements.sol#L3)
392 |
393 | ```solidity
394 | pragma solidity >=0.8.22;
395 | ```
396 |
397 | - Found in src/types/DataTypes.sol [Line: 2](../tests/2024-05-Sablier/v2-core/src/types/DataTypes.sol#L2)
398 |
399 | ```solidity
400 | pragma solidity >=0.8.22;
401 | ```
402 |
403 | </details>
404 |
405 |
406 |
407 | ## L-5: Large Numeric Literal
408 |
409 | Large literal values multiples of 10000 can be replaced with scientific notation.Use `e` notation, for example: `1e18`, instead of its full numeric value.
410 |
411 | <details><summary>2 Found Instances</summary>
412 |
413 |
414 | - Found in src/SablierV2NFTDescriptor.sol [Line: 200](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L200)
415 |
416 | ```solidity
417 | return streamedAmount * 10_000 / depositedAmount;
418 | ```
419 |
420 | - Found in src/libraries/SVGElements.sol [Line: 217](../tests/2024-05-Sablier/v2-core/src/libraries/SVGElements.sol#L217)
421 |
422 | ```solidity
423 | (10_000 - progressNumerical).toString(),
424 | ```
425 |
426 | </details>
427 |
428 |
429 |
430 | ## L-6: Internal Function Used Only Once
431 |
432 | 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.
433 |
434 | <details><summary>17 Found Instances</summary>
435 |
436 |
437 | - Found in src/SablierV2NFTDescriptor.sol [Line: 133](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L133)
438 |
439 | ```solidity
440 | function abbreviateAmount(uint256 amount, uint256 decimals) internal pure returns (string memory) {
441 | ```
442 |
443 | - Found in src/SablierV2NFTDescriptor.sol [Line: 171](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L171)
444 |
445 | ```solidity
446 | function calculateDurationInDays(uint256 startTime, uint256 endTime) internal pure returns (string memory) {
447 | ```
448 |
449 | - Found in src/SablierV2NFTDescriptor.sol [Line: 190](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L190)
450 |
451 | ```solidity
452 | function calculateStreamedPercentage(
453 | ```
454 |
455 | - Found in src/SablierV2NFTDescriptor.sol [Line: 206](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L206)
456 |
457 | ```solidity
458 | function generateAccentColor(address sablier, uint256 streamId) internal view returns (string memory) {
459 | ```
460 |
461 | - Found in src/SablierV2NFTDescriptor.sol [Line: 240](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L240)
462 |
463 | ```solidity
464 | function generateAttributes(
465 | ```
466 |
467 | - Found in src/SablierV2NFTDescriptor.sol [Line: 261](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L261)
468 |
469 | ```solidity
470 | function generateDescription(
471 | ```
472 |
473 | - Found in src/SablierV2NFTDescriptor.sol [Line: 301](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L301)
474 |
475 | ```solidity
476 | function generateName(string memory sablierModel, string memory streamId) internal pure returns (string memory) {
477 | ```
478 |
479 | - Found in src/SablierV2NFTDescriptor.sol [Line: 307](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L307)
480 |
481 | ```solidity
482 | function mapSymbol(IERC721Metadata sablier) internal view returns (string memory) {
483 | ```
484 |
485 | - Found in src/SablierV2NFTDescriptor.sol [Line: 322](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L322)
486 |
487 | ```solidity
488 | function safeAssetDecimals(address asset) internal view returns (uint8) {
489 | ```
490 |
491 | - Found in src/SablierV2NFTDescriptor.sol [Line: 334](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L334)
492 |
493 | ```solidity
494 | function safeAssetSymbol(address asset) internal view returns (string memory) {
495 | ```
496 |
497 | - Found in src/SablierV2NFTDescriptor.sol [Line: 372](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L372)
498 |
499 | ```solidity
500 | function stringifyPercentage(uint256 percentage) internal pure returns (string memory) {
501 | ```
502 |
503 | - Found in src/SablierV2NFTDescriptor.sol [Line: 384](../tests/2024-05-Sablier/v2-core/src/SablierV2NFTDescriptor.sol#L384)
504 |
505 | ```solidity
506 | function stringifyStatus(Lockup.Status status) internal pure returns (string memory) {
507 | ```
508 |
509 | - Found in src/libraries/NFTSVG.sol [Line: 98](../tests/2024-05-Sablier/v2-core/src/libraries/NFTSVG.sol#L98)
510 |
511 | ```solidity
512 | function generateDefs(
513 | ```
514 |
515 | - Found in src/libraries/NFTSVG.sol [Line: 120](../tests/2024-05-Sablier/v2-core/src/libraries/NFTSVG.sol#L120)
516 |
517 | ```solidity
518 | function generateFloatingText(
519 | ```
520 |
521 | - Found in src/libraries/NFTSVG.sol [Line: 146](../tests/2024-05-Sablier/v2-core/src/libraries/NFTSVG.sol#L146)
522 |
523 | ```solidity
524 | function generateHrefs(
525 | ```
526 |
527 | - Found in src/libraries/SVGElements.sol [Line: 78](../tests/2024-05-Sablier/v2-core/src/libraries/SVGElements.sol#L78)
528 |
529 | ```solidity
530 | function card(
531 | ```
532 |
533 | - Found in src/libraries/SVGElements.sol [Line: 255](../tests/2024-05-Sablier/v2-core/src/libraries/SVGElements.sol#L255)
534 |
535 | ```solidity
536 | function stringifyCardType(CardType cardType) internal pure returns (string memory) {
537 | ```
538 |
539 | </details>
540 |
541 |
542 |
543 | ## L-7: Loop Contains `require`/`revert`
544 |
545 | 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
546 |
547 | <details><summary>4 Found Instances</summary>
548 |
549 |
550 | - Found in src/abstracts/SablierV2Lockup.sol [Line: 277](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L277)
551 |
552 | ```solidity
553 | for (uint256 i = 0; i < count; ++i) {
554 | ```
555 |
556 | - Found in src/abstracts/SablierV2Lockup.sol [Line: 452](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L452)
557 |
558 | ```solidity
559 | for (uint256 i = 0; i < streamIdsCount; ++i) {
560 | ```
561 |
562 | - Found in src/libraries/Helpers.sol [Line: 252](../tests/2024-05-Sablier/v2-core/src/libraries/Helpers.sol#L252)
563 |
564 | ```solidity
565 | for (uint256 index = 0; index < count; ++index) {
566 | ```
567 |
568 | - Found in src/libraries/Helpers.sol [Line: 315](../tests/2024-05-Sablier/v2-core/src/libraries/Helpers.sol#L315)
569 |
570 | ```solidity
571 | for (uint256 index = 0; index < count; ++index) {
572 | ```
573 |
574 | </details>
575 |
576 |
577 |
578 | ## L-8: Costly operations inside loop
579 |
580 | Invoking `SSTORE` operations in loops may waste gas. Use a local variable to hold the loop computation result.
581 |
582 | <details><summary>4 Found Instances</summary>
583 |
584 |
585 | - Found in src/SablierV2LockupDynamic.sol [Line: 344](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupDynamic.sol#L344)
586 |
587 | ```solidity
588 | for (uint256 i = 0; i < segmentCount; ++i) {
589 | ```
590 |
591 | - Found in src/SablierV2LockupTranched.sol [Line: 248](../tests/2024-05-Sablier/v2-core/src/SablierV2LockupTranched.sol#L248)
592 |
593 | ```solidity
594 | for (uint256 i = 0; i < trancheCount; ++i) {
595 | ```
596 |
597 | - Found in src/abstracts/SablierV2Lockup.sol [Line: 277](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L277)
598 |
599 | ```solidity
600 | for (uint256 i = 0; i < count; ++i) {
601 | ```
602 |
603 | - Found in src/abstracts/SablierV2Lockup.sol [Line: 452](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L452)
604 |
605 | ```solidity
606 | for (uint256 i = 0; i < streamIdsCount; ++i) {
607 | ```
608 |
609 | </details>
610 |
611 |
612 |
613 | ## L-9: Unchecked Return
614 |
615 | Function returns a value but it is ignored. Consider checking the return value.
616 |
617 | <details><summary>1 Found Instances</summary>
618 |
619 |
620 | - Found in src/abstracts/SablierV2Lockup.sol [Line: 211](../tests/2024-05-Sablier/v2-core/src/abstracts/SablierV2Lockup.sol#L211)
621 |
622 | ```solidity
623 | _requireOwned({ tokenId: streamId });
624 | ```
625 |
626 | </details>
627 |
628 |
629 |
630 |
```
--------------------------------------------------------------------------------
/aderyn_core/src/detect/detector.rs:
--------------------------------------------------------------------------------
```rust
1 | use serde::{Deserialize, Serialize};
2 | use strum::{Display, EnumCount, EnumIter, EnumString};
3 |
4 | use crate::{
5 | ast::NodeID,
6 | context::workspace::WorkspaceContext,
7 | detect::{high::*, low::*},
8 | };
9 |
10 | use std::{
11 | collections::BTreeMap,
12 | error::Error,
13 | fmt::{self, Display},
14 | str::FromStr,
15 | };
16 |
17 | pub fn get_all_issue_detectors() -> Vec<Box<dyn IssueDetector>> {
18 | vec![
19 | Box::<DelegatecallInLoopDetector>::default(),
20 | Box::<CentralizationRiskDetector>::default(),
21 | Box::<SolmateSafeTransferLibDetector>::default(),
22 | Box::<AvoidAbiEncodePackedDetector>::default(),
23 | Box::<EcrecoverDetector>::default(),
24 | Box::<DeprecatedOZFunctionDetector>::default(),
25 | Box::<UnsafeERC20OperationDetector>::default(),
26 | Box::<UnspecificSolidityPragmaDetector>::default(),
27 | Box::<StateNoAddressCheckDetector>::default(),
28 | Box::<UnusedPublicFunctionDetector>::default(),
29 | Box::<LiteralsInsteadOfConstantsDetector>::default(),
30 | Box::<EmptyRequireRevertDetector>::default(),
31 | Box::<NonReentrantBeforeOthersDetector>::default(),
32 | Box::<BlockTimestampDeadlineDetector>::default(),
33 | Box::<UnsafeERC721MintDetector>::default(),
34 | Box::<PushZeroOpcodeDetector>::default(),
35 | Box::<ArbitraryTransferFromDetector>::default(),
36 | Box::<ModifierUsedOnlyOnceDetector>::default(),
37 | Box::<EmptyBlockDetector>::default(),
38 | Box::<LargeLiteralValueDetector>::default(),
39 | Box::<InternalFunctionUsedOnceDetector>::default(),
40 | Box::<TodoDetector>::default(),
41 | Box::<InconsistentTypeNamesDetector>::default(),
42 | Box::<UnprotectedInitializerDetector>::default(),
43 | Box::<UnusedErrorDetector>::default(),
44 | Box::<RequireRevertInLoopDetector>::default(),
45 | Box::<DivisionBeforeMultiplicationDetector>::default(),
46 | Box::<UnsafeCastingDetector>::default(),
47 | Box::<EnumerableLoopRemovalDetector>::default(),
48 | Box::<ExperimentalEncoderDetector>::default(),
49 | Box::<IncorrectShiftOrderDetector>::default(),
50 | Box::<StorageArrayMemoryEditDetector>::default(),
51 | Box::<MultipleConstructorsDetector>::default(),
52 | Box::<ReusedContractNameDetector>::default(),
53 | Box::<NestedStructInMappingDetector>::default(),
54 | Box::<SelfdestructDetector>::default(),
55 | Box::<DynamicArrayLengthAssignmentDetector>::default(),
56 | Box::<IncorrectUseOfCaretOperatorDetector>::default(),
57 | Box::<YulReturnDetector>::default(),
58 | Box::<StateVariableShadowingDetector>::default(),
59 | Box::<UncheckedSendDetector>::default(),
60 | Box::<MisusedBooleanDetector>::default(),
61 | Box::<SendEtherNoChecksDetector>::default(),
62 | Box::<DelegateCallUncheckedAddressDetector>::default(),
63 | Box::<TautologicalCompareDetector>::default(),
64 | Box::<RTLODetector>::default(),
65 | Box::<DangerousUnaryOperatorDetector>::default(),
66 | Box::<TautologyOrContraditionDetector>::default(),
67 | Box::<DangerousStrictEqualityOnBalanceDetector>::default(),
68 | Box::<StorageSignedIntegerArrayDetector>::default(),
69 | Box::<RedundantStatementDetector>::default(),
70 | Box::<StateVariableReadExternalDetector>::default(),
71 | Box::<WeakRandomnessDetector>::default(),
72 | Box::<PreDeclaredLocalVariableUsageDetector>::default(),
73 | Box::<DeletionNestedMappingDetector>::default(),
74 | Box::<UnusedStateVariablesDetector>::default(),
75 | Box::<ConstantFunctionContainsAssemblyDetector>::default(),
76 | Box::<BooleanEqualityDetector>::default(),
77 | Box::<TxOriginUsedForAuthDetector>::default(),
78 | Box::<MsgValueUsedInLoopDetector>::default(),
79 | Box::<ContractLocksEtherDetector>::default(),
80 | Box::<LocalVariableShadowingDetector>::default(),
81 | Box::<IncorrectERC721InterfaceDetector>::default(),
82 | Box::<IncorrectERC20InterfaceDetector>::default(),
83 | Box::<UninitializedLocalVariableDetector>::default(),
84 | Box::<ReturnBombDetector>::default(),
85 | Box::<OutOfOrderRetryableDetector>::default(),
86 | Box::<FunctionInitializingStateDetector>::default(),
87 | Box::<DeadCodeDetector>::default(),
88 | Box::<CacheArrayLengthDetector>::default(),
89 | Box::<AssertStateChangeDetector>::default(),
90 | Box::<CostlyLoopDetector>::default(),
91 | Box::<ConstantFunctionChangesStateDetector>::default(),
92 | Box::<BuiltinSymbolShadowingDetector>::default(),
93 | Box::<VoidConstructorDetector>::default(),
94 | Box::<FunctionSelectorCollisionDetector>::default(),
95 | Box::<MissingInheritanceDetector>::default(),
96 | Box::<UnusedImportDetector>::default(),
97 | Box::<UncheckedLowLevelCallDetector>::default(),
98 | Box::<FunctionPointerInConstructorDetector>::default(),
99 | Box::<StateVariableCouldBeConstantDetector>::default(),
100 | Box::<StateVariableChangesWithoutEventDetector>::default(),
101 | Box::<StateVariableCouldBeImmutableDetector>::default(),
102 | Box::<MultiplePlaceholdersDetector>::default(),
103 | Box::<ReentrancyStateChangeDetector>::default(),
104 | Box::<IncorrectUseOfModifierDetector>::default(),
105 | Box::<UncheckedReturnDetector>::default(),
106 | ]
107 | }
108 |
109 | pub fn get_all_detectors_names() -> Vec<String> {
110 | get_all_issue_detectors().iter().map(|d| d.name()).collect()
111 | }
112 |
113 | // Note to maintainers: DO NOT CHANGE THE ORDER OF THESE DERIVE ATTRIBUTES
114 | #[derive(Debug, PartialEq, EnumString, Display)]
115 | #[strum(serialize_all = "kebab-case")]
116 | pub enum IssueDetectorNamePool {
117 | IncorrectUseOfModifier,
118 | ReentrancyStateChange,
119 | StateVariableCouldBeImmutable,
120 | MultiplePlaceholders,
121 | StateChangeWithoutEvent,
122 | MissingInheritance,
123 | UnusedImport,
124 | VoidConstructor,
125 | UncheckedLowLevelCall,
126 | FunctionPointerInConstructor,
127 | DeadCode,
128 | FunctionSelectorCollision,
129 | StorageArrayLengthNotCached,
130 | AssertStateChange,
131 | CostlyLoop,
132 | ConstantFunctionChangesState,
133 | BuiltinSymbolShadowing,
134 | IncorrectERC721Interface,
135 | FunctionInitializingState,
136 | DelegatecallInLoop,
137 | CentralizationRisk,
138 | SolmateSafeTransferLib,
139 | AbiEncodePackedHashCollision,
140 | Ecrecover,
141 | DeprecatedOzFunction,
142 | UnsafeERC20Operation,
143 | UnspecificSolidityPragma,
144 | StateNoAddressCheck,
145 | UnusedPublicFunction,
146 | EmptyRequireRevert,
147 | NonReentrantNotFirst,
148 | BlockTimestampDeadline,
149 | LiteralInsteadOfConstant,
150 | UnsafeOzERC721Mint,
151 | PushZeroOpcode,
152 | ArbitraryTransferFrom,
153 | ModifierUsedOnlyOnce,
154 | UnusedError,
155 | LargeNumericLiteral,
156 | InternalFunctionUsedOnce,
157 | EmptyBlock,
158 | Todo,
159 | InconsistentTypeNames,
160 | UnprotectedInitializer,
161 | RequireRevertInLoop,
162 | DivisionBeforeMultiplication,
163 | UnsafeCasting,
164 | EnumerableLoopRemoval,
165 | ExperimentalEncoder,
166 | IncorrectShiftOrder,
167 | StorageArrayMemoryEdit,
168 | MultipleConstructors,
169 | ReusedContractName,
170 | NestedStructInMapping,
171 | Selfdestruct,
172 | DynamicArrayLengthAssignment,
173 | IncorrectCaretOperator,
174 | YulReturn,
175 | StateVariableShadowing,
176 | UncheckedSend,
177 | MisusedBoolean,
178 | EthSendUncheckedAddress,
179 | DelegateCallUncheckedAddress,
180 | TautologicalCompare,
181 | #[allow(clippy::upper_case_acronyms)]
182 | RTLO,
183 | UncheckedReturn,
184 | DangerousUnaryOperator,
185 | TautologyOrContradiction,
186 | StrictEqualityContractBalance,
187 | SignedIntegerStorageArray,
188 | RedundantStatement,
189 | StateVariableReadExternal,
190 | WeakRandomness,
191 | PreDeclaredLocalVariableUsage,
192 | DeleteNestedMapping,
193 | UnusedStateVariable,
194 | ConstantFunctionContainsAssembly,
195 | BooleanEquality,
196 | TxOriginUsedForAuth,
197 | MsgValueInLoop,
198 | ContractLocksEther,
199 | LocalVariableShadowing,
200 | IncorrectERC20Interface,
201 | UninitializedLocalVariable,
202 | ReturnBomb,
203 | OutOfOrderRetryable,
204 | StateVariableCouldBeConstant,
205 | // NOTE: `Undecided` will be the default name (for new bots).
206 | // If it's accepted, a new variant will be added to this enum before normalizing it in aderyn
207 | Undecided,
208 | }
209 |
210 | pub fn request_issue_detector_by_name(detector_name: &str) -> Option<Box<dyn IssueDetector>> {
211 | // Expects a valid detector_name
212 | let detector_name = IssueDetectorNamePool::from_str(detector_name).ok()?;
213 | match detector_name {
214 | IssueDetectorNamePool::ReentrancyStateChange => {
215 | Some(Box::<ReentrancyStateChangeDetector>::default())
216 | }
217 | IssueDetectorNamePool::IncorrectUseOfModifier => {
218 | Some(Box::<IncorrectUseOfModifierDetector>::default())
219 | }
220 | IssueDetectorNamePool::StateVariableCouldBeImmutable => {
221 | Some(Box::<StateVariableCouldBeImmutableDetector>::default())
222 | }
223 | IssueDetectorNamePool::MultiplePlaceholders => {
224 | Some(Box::<MultiplePlaceholdersDetector>::default())
225 | }
226 | IssueDetectorNamePool::StateChangeWithoutEvent => {
227 | Some(Box::<StateVariableChangesWithoutEventDetector>::default())
228 | }
229 | IssueDetectorNamePool::MissingInheritance => {
230 | Some(Box::<MissingInheritanceDetector>::default())
231 | }
232 | IssueDetectorNamePool::LocalVariableShadowing => {
233 | Some(Box::<LocalVariableShadowingDetector>::default())
234 | }
235 | IssueDetectorNamePool::UnusedImport => Some(Box::<UnusedImportDetector>::default()),
236 | IssueDetectorNamePool::VoidConstructor => Some(Box::<VoidConstructorDetector>::default()),
237 | IssueDetectorNamePool::StateVariableCouldBeConstant => {
238 | Some(Box::<StateVariableCouldBeConstantDetector>::default())
239 | }
240 | IssueDetectorNamePool::LiteralInsteadOfConstant => {
241 | Some(Box::<LiteralsInsteadOfConstantsDetector>::default())
242 | }
243 | IssueDetectorNamePool::FunctionPointerInConstructor => {
244 | Some(Box::<FunctionPointerInConstructorDetector>::default())
245 | }
246 | IssueDetectorNamePool::DeadCode => Some(Box::<DeadCodeDetector>::default()),
247 | IssueDetectorNamePool::FunctionSelectorCollision => {
248 | Some(Box::<FunctionSelectorCollisionDetector>::default())
249 | }
250 | IssueDetectorNamePool::StorageArrayLengthNotCached => {
251 | Some(Box::<CacheArrayLengthDetector>::default())
252 | }
253 | IssueDetectorNamePool::AssertStateChange => {
254 | Some(Box::<AssertStateChangeDetector>::default())
255 | }
256 | IssueDetectorNamePool::CostlyLoop => Some(Box::<CostlyLoopDetector>::default()),
257 | IssueDetectorNamePool::ConstantFunctionChangesState => {
258 | Some(Box::<ConstantFunctionChangesStateDetector>::default())
259 | }
260 | IssueDetectorNamePool::BuiltinSymbolShadowing => {
261 | Some(Box::<BuiltinSymbolShadowingDetector>::default())
262 | }
263 | IssueDetectorNamePool::IncorrectERC721Interface => {
264 | Some(Box::<IncorrectERC721InterfaceDetector>::default())
265 | }
266 | IssueDetectorNamePool::OutOfOrderRetryable => {
267 | Some(Box::<OutOfOrderRetryableDetector>::default())
268 | }
269 | IssueDetectorNamePool::FunctionInitializingState => {
270 | Some(Box::<FunctionInitializingStateDetector>::default())
271 | }
272 | IssueDetectorNamePool::IncorrectERC20Interface => {
273 | Some(Box::<IncorrectERC20InterfaceDetector>::default())
274 | }
275 | IssueDetectorNamePool::UninitializedLocalVariable => {
276 | Some(Box::<UninitializedLocalVariableDetector>::default())
277 | }
278 | IssueDetectorNamePool::ReturnBomb => Some(Box::<ReturnBombDetector>::default()),
279 | IssueDetectorNamePool::UnusedStateVariable => {
280 | Some(Box::<UnusedStateVariablesDetector>::default())
281 | }
282 | IssueDetectorNamePool::DelegatecallInLoop => {
283 | Some(Box::<DelegatecallInLoopDetector>::default())
284 | }
285 | IssueDetectorNamePool::CentralizationRisk => {
286 | Some(Box::<CentralizationRiskDetector>::default())
287 | }
288 | IssueDetectorNamePool::SolmateSafeTransferLib => {
289 | Some(Box::<SolmateSafeTransferLibDetector>::default())
290 | }
291 | IssueDetectorNamePool::AbiEncodePackedHashCollision => {
292 | Some(Box::<AvoidAbiEncodePackedDetector>::default())
293 | }
294 | IssueDetectorNamePool::Ecrecover => Some(Box::<EcrecoverDetector>::default()),
295 | IssueDetectorNamePool::DeprecatedOzFunction => {
296 | Some(Box::<DeprecatedOZFunctionDetector>::default())
297 | }
298 | IssueDetectorNamePool::UnsafeERC20Operation => {
299 | Some(Box::<UnsafeERC20OperationDetector>::default())
300 | }
301 | IssueDetectorNamePool::UnspecificSolidityPragma => {
302 | Some(Box::<UnspecificSolidityPragmaDetector>::default())
303 | }
304 | IssueDetectorNamePool::StateNoAddressCheck => {
305 | Some(Box::<StateNoAddressCheckDetector>::default())
306 | }
307 | IssueDetectorNamePool::UnusedPublicFunction => {
308 | Some(Box::<UnusedPublicFunctionDetector>::default())
309 | }
310 | IssueDetectorNamePool::EmptyRequireRevert => {
311 | Some(Box::<EmptyRequireRevertDetector>::default())
312 | }
313 | IssueDetectorNamePool::NonReentrantNotFirst => {
314 | Some(Box::<NonReentrantBeforeOthersDetector>::default())
315 | }
316 | IssueDetectorNamePool::BlockTimestampDeadline => {
317 | Some(Box::<BlockTimestampDeadlineDetector>::default())
318 | }
319 | IssueDetectorNamePool::UnsafeOzERC721Mint => {
320 | Some(Box::<UnsafeERC721MintDetector>::default())
321 | }
322 | IssueDetectorNamePool::PushZeroOpcode => Some(Box::<PushZeroOpcodeDetector>::default()),
323 | IssueDetectorNamePool::ArbitraryTransferFrom => {
324 | Some(Box::<ArbitraryTransferFromDetector>::default())
325 | }
326 | IssueDetectorNamePool::ModifierUsedOnlyOnce => {
327 | Some(Box::<ModifierUsedOnlyOnceDetector>::default())
328 | }
329 | IssueDetectorNamePool::LargeNumericLiteral => {
330 | Some(Box::<LargeLiteralValueDetector>::default())
331 | }
332 | IssueDetectorNamePool::InternalFunctionUsedOnce => {
333 | Some(Box::<InternalFunctionUsedOnceDetector>::default())
334 | }
335 | IssueDetectorNamePool::EmptyBlock => Some(Box::<EmptyBlockDetector>::default()),
336 | IssueDetectorNamePool::Todo => Some(Box::<TodoDetector>::default()),
337 | IssueDetectorNamePool::InconsistentTypeNames => {
338 | Some(Box::<InconsistentTypeNamesDetector>::default())
339 | }
340 | IssueDetectorNamePool::UnprotectedInitializer => {
341 | Some(Box::<UnprotectedInitializerDetector>::default())
342 | }
343 | IssueDetectorNamePool::RequireRevertInLoop => {
344 | Some(Box::<RequireRevertInLoopDetector>::default())
345 | }
346 | IssueDetectorNamePool::UnusedError => Some(Box::<UnusedErrorDetector>::default()),
347 | IssueDetectorNamePool::DivisionBeforeMultiplication => {
348 | Some(Box::<DivisionBeforeMultiplicationDetector>::default())
349 | }
350 | IssueDetectorNamePool::UnsafeCasting => Some(Box::<UnsafeCastingDetector>::default()),
351 | IssueDetectorNamePool::EnumerableLoopRemoval => {
352 | Some(Box::<EnumerableLoopRemovalDetector>::default())
353 | }
354 | IssueDetectorNamePool::ExperimentalEncoder => {
355 | Some(Box::<ExperimentalEncoderDetector>::default())
356 | }
357 | IssueDetectorNamePool::IncorrectShiftOrder => {
358 | Some(Box::<IncorrectShiftOrderDetector>::default())
359 | }
360 | IssueDetectorNamePool::StorageArrayMemoryEdit => {
361 | Some(Box::<StorageArrayMemoryEditDetector>::default())
362 | }
363 | IssueDetectorNamePool::MultipleConstructors => {
364 | Some(Box::<MultipleConstructorsDetector>::default())
365 | }
366 | IssueDetectorNamePool::ReusedContractName => {
367 | Some(Box::<ReusedContractNameDetector>::default())
368 | }
369 | IssueDetectorNamePool::NestedStructInMapping => {
370 | Some(Box::<NestedStructInMappingDetector>::default())
371 | }
372 | IssueDetectorNamePool::Selfdestruct => Some(Box::<SelfdestructDetector>::default()),
373 | IssueDetectorNamePool::DynamicArrayLengthAssignment => {
374 | Some(Box::<DynamicArrayLengthAssignmentDetector>::default())
375 | }
376 |
377 | IssueDetectorNamePool::IncorrectCaretOperator => {
378 | Some(Box::<IncorrectUseOfCaretOperatorDetector>::default())
379 | }
380 | IssueDetectorNamePool::YulReturn => Some(Box::<YulReturnDetector>::default()),
381 | IssueDetectorNamePool::StateVariableShadowing => {
382 | Some(Box::<StateVariableShadowingDetector>::default())
383 | }
384 | IssueDetectorNamePool::UncheckedSend => Some(Box::<UncheckedSendDetector>::default()),
385 | IssueDetectorNamePool::MisusedBoolean => Some(Box::<MisusedBooleanDetector>::default()),
386 | IssueDetectorNamePool::EthSendUncheckedAddress => {
387 | Some(Box::<SendEtherNoChecksDetector>::default())
388 | }
389 | IssueDetectorNamePool::DelegateCallUncheckedAddress => {
390 | Some(Box::<DelegateCallUncheckedAddressDetector>::default())
391 | }
392 | IssueDetectorNamePool::TautologicalCompare => {
393 | Some(Box::<TautologicalCompareDetector>::default())
394 | }
395 | IssueDetectorNamePool::RTLO => Some(Box::<RTLODetector>::default()),
396 | IssueDetectorNamePool::UncheckedReturn => Some(Box::<UncheckedReturnDetector>::default()),
397 | IssueDetectorNamePool::DangerousUnaryOperator => {
398 | Some(Box::<DangerousUnaryOperatorDetector>::default())
399 | }
400 | IssueDetectorNamePool::TautologyOrContradiction => {
401 | Some(Box::<TautologyOrContraditionDetector>::default())
402 | }
403 | IssueDetectorNamePool::StrictEqualityContractBalance => {
404 | Some(Box::<DangerousStrictEqualityOnBalanceDetector>::default())
405 | }
406 | IssueDetectorNamePool::SignedIntegerStorageArray => {
407 | Some(Box::<StorageSignedIntegerArrayDetector>::default())
408 | }
409 | IssueDetectorNamePool::RedundantStatement => {
410 | Some(Box::<RedundantStatementDetector>::default())
411 | }
412 | IssueDetectorNamePool::StateVariableReadExternal => {
413 | Some(Box::<StateVariableReadExternalDetector>::default())
414 | }
415 | IssueDetectorNamePool::WeakRandomness => Some(Box::<WeakRandomnessDetector>::default()),
416 | IssueDetectorNamePool::PreDeclaredLocalVariableUsage => {
417 | Some(Box::<PreDeclaredLocalVariableUsageDetector>::default())
418 | }
419 | IssueDetectorNamePool::DeleteNestedMapping => {
420 | Some(Box::<DeletionNestedMappingDetector>::default())
421 | }
422 | IssueDetectorNamePool::ConstantFunctionContainsAssembly => {
423 | Some(Box::<ConstantFunctionContainsAssemblyDetector>::default())
424 | }
425 | IssueDetectorNamePool::BooleanEquality => Some(Box::<BooleanEqualityDetector>::default()),
426 | IssueDetectorNamePool::TxOriginUsedForAuth => {
427 | Some(Box::<TxOriginUsedForAuthDetector>::default())
428 | }
429 | IssueDetectorNamePool::MsgValueInLoop => Some(Box::<MsgValueUsedInLoopDetector>::default()),
430 | IssueDetectorNamePool::ContractLocksEther => {
431 | Some(Box::<ContractLocksEtherDetector>::default())
432 | }
433 | IssueDetectorNamePool::UncheckedLowLevelCall => {
434 | Some(Box::<UncheckedLowLevelCallDetector>::default())
435 | }
436 | IssueDetectorNamePool::Undecided => None,
437 | }
438 | }
439 |
440 | pub fn get_issue_detector_by_name(detector_name: &str) -> Box<dyn IssueDetector> {
441 | request_issue_detector_by_name(detector_name).unwrap()
442 | }
443 |
444 | #[derive(Debug, PartialEq, Serialize, Deserialize, EnumCount, Clone, EnumIter)]
445 | pub enum IssueSeverity {
446 | Low,
447 | High,
448 | }
449 |
450 | impl Display for IssueSeverity {
451 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
452 | let issue_description = match self {
453 | IssueSeverity::Low => "Low",
454 | IssueSeverity::High => "High",
455 | };
456 | write!(f, "{}", issue_description).unwrap();
457 | Ok(())
458 | }
459 | }
460 |
461 | impl dyn IssueDetector {
462 | pub fn skeletal_clone(&self) -> Box<dyn IssueDetector> {
463 | request_issue_detector_by_name(self.name().as_str()).unwrap()
464 | }
465 | }
466 |
467 | pub trait IssueDetector: Send + Sync + 'static {
468 | fn detect(&mut self, _context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
469 | Ok(true)
470 | }
471 |
472 | fn severity(&self) -> IssueSeverity {
473 | IssueSeverity::High
474 | }
475 |
476 | fn title(&self) -> String {
477 | String::from("Title")
478 | }
479 |
480 | fn description(&self) -> String {
481 | String::from("Description")
482 | }
483 |
484 | fn name(&self) -> String {
485 | format!("{}", IssueDetectorNamePool::Undecided)
486 | }
487 |
488 | // Keys are source file name, line number and source location
489 | // Value is ASTNode NodeID
490 | fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
491 | BTreeMap::new()
492 | }
493 |
494 | fn hints(&self) -> BTreeMap<(String, usize, String), String> {
495 | BTreeMap::new()
496 | }
497 | }
498 |
```
--------------------------------------------------------------------------------
/aderyn_core/src/detect/high/tautology_or_contradiction.rs:
--------------------------------------------------------------------------------
```rust
1 | use std::{collections::BTreeMap, error::Error};
2 |
3 | use crate::ast::{BinaryOperation, NodeID, TypeDescriptions};
4 |
5 | use crate::{
6 | capture,
7 | context::workspace::WorkspaceContext,
8 | detect::{
9 | detector::{IssueDetector, IssueDetectorNamePool, IssueSeverity},
10 | helpers::get_literal_value_or_constant_variable_value,
11 | },
12 | };
13 | use eyre::Result;
14 | use solidity_integer_helper::{
15 | does_operation_make_sense_with_lhs_value, does_operation_make_sense_with_rhs_value,
16 | };
17 |
18 | #[derive(Default)]
19 | pub struct TautologyOrContraditionDetector {
20 | // Keys are: [0] source file name, [1] line number, [2] character location of node.
21 | // Do not add items manually, use `capture!` to add nodes to this BTreeMap.
22 | found_instances: BTreeMap<(String, usize, String), NodeID>,
23 | }
24 |
25 | impl IssueDetector for TautologyOrContraditionDetector {
26 | fn detect(&mut self, context: &WorkspaceContext) -> Result<bool, Box<dyn Error>> {
27 | for binary_operation in context.binary_operations() {
28 | if let Some(is_tautlogy_or_contradiction) =
29 | binary_operation.is_tautology_or_contradiction(context)
30 | && is_tautlogy_or_contradiction
31 | {
32 | capture!(self, context, binary_operation);
33 | }
34 | }
35 |
36 | Ok(!self.found_instances.is_empty())
37 | }
38 |
39 | fn severity(&self) -> IssueSeverity {
40 | IssueSeverity::High
41 | }
42 |
43 | fn title(&self) -> String {
44 | String::from("Tautology or Contradiction in comparison")
45 | }
46 |
47 | fn description(&self) -> String {
48 | String::from(
49 | "The condition has been determined to be either always true or always false due to the integer range in which we're operating.",
50 | )
51 | }
52 |
53 | fn instances(&self) -> BTreeMap<(String, usize, String), NodeID> {
54 | self.found_instances.clone()
55 | }
56 |
57 | fn name(&self) -> String {
58 | IssueDetectorNamePool::TautologyOrContradiction.to_string()
59 | }
60 | }
61 |
62 | #[cfg(test)]
63 | mod tautology_or_contradiction_tests {
64 |
65 | use crate::detect::{
66 | detector::IssueDetector, high::tautology_or_contradiction::TautologyOrContraditionDetector,
67 | };
68 |
69 | #[test]
70 |
71 | fn test_tautology_or_contradiction_detector() {
72 | let context = crate::detect::test_utils::load_solidity_source_unit(
73 | "../tests/contract-playground/src/TautologyOrContradiction.sol",
74 | );
75 |
76 | let mut detector = TautologyOrContraditionDetector::default();
77 | let found = detector.detect(&context).unwrap();
78 | assert!(found);
79 | assert_eq!(detector.instances().len(), 2);
80 | }
81 | }
82 |
83 | pub trait OperationIsTautologyOrContradiction {
84 | fn is_tautology_or_contradiction(&self, context: &WorkspaceContext) -> Option<bool>;
85 | }
86 |
87 | impl OperationIsTautologyOrContradiction for BinaryOperation {
88 | fn is_tautology_or_contradiction(&self, context: &WorkspaceContext) -> Option<bool> {
89 | if let (
90 | Some(TypeDescriptions { type_string: Some(lhs_type_string), .. }),
91 | Some(TypeDescriptions { type_string: Some(rhs_type_string), .. }),
92 | operator,
93 | ) = (
94 | self.left_expression.as_ref().type_descriptions(),
95 | self.right_expression.as_ref().type_descriptions(),
96 | self.operator.clone(),
97 | ) {
98 | let supported_operators = [">", ">=", "<", "<="];
99 | if supported_operators.into_iter().all(|op| op != operator) {
100 | return None;
101 | }
102 |
103 | if let Some(lhs_value) = get_literal_value_or_constant_variable_value(
104 | self.left_expression.get_node_id()?,
105 | context,
106 | ) && let Some(makes_sense) =
107 | does_operation_make_sense_with_lhs_value(&lhs_value, &operator, rhs_type_string)
108 | && !makes_sense
109 | {
110 | return Some(true);
111 | }
112 |
113 | if let Some(rhs_value) = get_literal_value_or_constant_variable_value(
114 | self.right_expression.get_node_id()?,
115 | context,
116 | ) && let Some(makes_sense) =
117 | does_operation_make_sense_with_rhs_value(lhs_type_string, &operator, &rhs_value)
118 | && !makes_sense
119 | {
120 | return Some(true);
121 | }
122 | }
123 |
124 | None
125 | }
126 | }
127 |
128 | pub mod solidity_integer_helper {
129 | use num_bigint::BigInt;
130 | use num_traits::One;
131 | use std::{error::Error, ops::Neg};
132 |
133 | /// This data type is big enough to handle the extreme values of uint256 and int256
134 | /// (Tests below)
135 | #[derive(PartialEq, Debug, Clone)]
136 | pub struct SolidityNumberRange {
137 | min_val: BigInt,
138 | max_val: BigInt,
139 | }
140 |
141 | impl SolidityNumberRange {
142 | fn fully_contains(&self, other_solidity_number_range: &SolidityNumberRange) -> bool {
143 | (self.min_val <= other_solidity_number_range.min_val)
144 | && (self.max_val >= other_solidity_number_range.max_val)
145 | }
146 |
147 | fn fully_excludes(&self, other_solidity_number_range: &SolidityNumberRange) -> bool {
148 | (other_solidity_number_range.max_val < self.min_val)
149 | || (other_solidity_number_range.min_val > self.max_val)
150 | }
151 | }
152 |
153 | /// Does this make sense? (boolean answer)
154 | /// ```no_code
155 | /// if(?uintX, operator, value)
156 | /// ```
157 | ///
158 | /// Example (ways to call this function)
159 | ///
160 | /// Say x is uint8:
161 | /// Then, when we come across a binary operation like follows:
162 | /// x >= 300
163 | /// we can determine if it makes sense by calling this function
164 | /// does_operation_make_sense_with_rhs_value("uint8", ">=", "300")
165 | ///
166 | /// This function checks for the range of integer values of uint8 and returns true if it is
167 | /// neither a tautology nor a contradiction.
168 | ///
169 | /// Here, I define tautology as the condition where the range Ex: (>=300) FULLY COVERS the Range
170 | /// of Uint8 Contradiction: When the range Ex:(>=300) fully excludes the Range of Uint8
171 | ///
172 | /// Notice how in the above example, the value is on the right hand side.
173 | /// Hence this function is called "does_...rhs_value".
174 | pub fn does_operation_make_sense_with_rhs_value(
175 | type_string: &str,
176 | operator: &str,
177 | value: &str,
178 | ) -> Option<bool> {
179 | let allowed_range = get_range_for_type_string(type_string).ok()?;
180 | let allowed_min_val = allowed_range.min_val.clone();
181 | let allowed_max_val = allowed_range.max_val.clone();
182 |
183 | let value_as_big_int = BigInt::parse_bytes(value.as_bytes(), 10)?;
184 |
185 | // First and foremost if the value is out of range it's 100% either a tautology or a
186 | // contradiction. Hence, return false.
187 | if value_as_big_int < allowed_min_val || value_as_big_int > allowed_max_val {
188 | return Some(false);
189 | }
190 | // At this point, we know that the value we are comparing to, is in the allowed range.
191 | // Now, we can get the represented range, and see if it fully contains the allowed range
192 | // (tatutology) or fully excludes the allowed range (contradiction)
193 | let represented_range = {
194 | match operator {
195 | ">=" => Some(SolidityNumberRange {
196 | min_val: value_as_big_int.clone(),
197 | max_val: allowed_max_val.clone(),
198 | }),
199 | ">" => Some(SolidityNumberRange {
200 | min_val: value_as_big_int.clone() + BigInt::one(),
201 | max_val: allowed_max_val.clone(),
202 | }),
203 | "<=" => Some(SolidityNumberRange {
204 | min_val: allowed_min_val.clone(),
205 | max_val: value_as_big_int.clone(),
206 | }),
207 | "<" => Some(SolidityNumberRange {
208 | min_val: allowed_min_val.clone(),
209 | max_val: value_as_big_int.clone() - BigInt::one(),
210 | }),
211 | &_ => None,
212 | }
213 | };
214 |
215 | if let Some(represented_range) = represented_range {
216 | return Some(
217 | !(represented_range.fully_contains(&allowed_range)
218 | || represented_range.fully_excludes(&allowed_range)),
219 | );
220 | }
221 |
222 | None
223 | }
224 |
225 | /// Does this make sense? (boolean answer)
226 | /// ```no_code
227 | /// if(value, operator, uint8?)
228 | /// ```
229 | ///
230 | /// Take advantage of the above method by reusing code
231 | ///
232 | /// Example (ways to call this function)
233 | ///
234 | /// Say x is uint8:
235 | /// Then, when we come across a binary operation like follows:
236 | /// 300 >= x
237 | /// we can determine if it makes sense by calling this function
238 | /// does_operation_make_sense_with_lhs_value("300", ">=", "uint8")
239 | ///
240 | /// Notice, here the value 300 is on the left hand side.
241 | pub fn does_operation_make_sense_with_lhs_value(
242 | value: &str,
243 | operator: &str,
244 | type_string: &str,
245 | ) -> Option<bool> {
246 | let inverse_operator = {
247 | match operator {
248 | ">=" => Some("<="),
249 | "<=" => Some(">="),
250 | ">" => Some("<"),
251 | "<" => Some(">"),
252 | _ => None,
253 | }
254 | }?;
255 | does_operation_make_sense_with_rhs_value(type_string, inverse_operator, value)
256 | }
257 |
258 | /// Accept the type string to calculate the range.
259 | pub fn get_range_for_type_string(
260 | type_string: &str,
261 | ) -> Result<SolidityNumberRange, Box<dyn Error>> {
262 | if type_string.starts_with("uint") {
263 | if let Some((_, num_of_bits)) = &type_string.split_once("uint") {
264 | let num_of_bits = num_of_bits.parse::<u32>()?;
265 | return Ok(SolidityNumberRange {
266 | min_val: find_uint_min(num_of_bits),
267 | max_val: find_uint_max(num_of_bits),
268 | });
269 | }
270 | } else if type_string.starts_with("int")
271 | && let Some((_, num_of_bits)) = &type_string.split_once("int")
272 | {
273 | let num_of_bits = num_of_bits.parse::<u32>()?;
274 | return Ok(SolidityNumberRange {
275 | min_val: find_int_min(num_of_bits),
276 | max_val: find_int_max(num_of_bits),
277 | });
278 | }
279 | Err("Invalid type string provided!".into())
280 | }
281 |
282 | // Helpers to calculate min and max for uint types like uint8, uint16, uint24, and so on . . .
283 |
284 | fn find_uint_max(num_of_bits: u32) -> BigInt {
285 | BigInt::parse_bytes(b"2", 10).unwrap().pow(num_of_bits) - BigInt::one()
286 | }
287 |
288 | fn find_uint_min(_: u32) -> BigInt {
289 | BigInt::ZERO
290 | }
291 |
292 | // Helpers to calculate min and max for int types like int8, int16, int24, and so on . . .
293 |
294 | fn find_int_max(num_of_bits: u32) -> BigInt {
295 | BigInt::parse_bytes(b"2", 10).unwrap().pow(num_of_bits - 1) - BigInt::one()
296 | }
297 |
298 | fn find_int_min(num_of_bits: u32) -> BigInt {
299 | BigInt::parse_bytes(b"2", 10).unwrap().pow(num_of_bits - 1).neg()
300 | }
301 |
302 | #[cfg(test)]
303 | mod test_num_bigint_primitives {
304 |
305 | use std::ops::Neg;
306 |
307 | use num_bigint::BigInt;
308 | use num_traits::{FromPrimitive, One};
309 |
310 | use crate::detect::high::tautology_or_contradiction::solidity_integer_helper::{
311 | does_operation_make_sense_with_rhs_value, find_int_max, find_int_min, find_uint_max,
312 | };
313 |
314 | use super::{
315 | SolidityNumberRange, does_operation_make_sense_with_lhs_value,
316 | get_range_for_type_string,
317 | };
318 |
319 | /*
320 | Tests to ensure that num_bigint crate holds the capacity to work with numbers
321 | in the range that Solidity language operates in.
322 | */
323 |
324 | #[test]
325 | fn test_2_raised_to_3() {
326 | let two_raised_to_three = BigInt::parse_bytes(b"2", 10).unwrap().pow(3);
327 | assert_eq!(two_raised_to_three, BigInt::from_u8(8).unwrap());
328 | }
329 |
330 | #[test]
331 | fn can_find_max_of_uint256() {
332 | // This test shows that we can calculate the biggest possible number in Solidity for
333 | // uint which is 2^256 - 1.
334 | // hence we conclude that because we can represent 2^256 - 1, we can easily cover all
335 | // the smaller variants of uint that is uint8, uint16, .... all the ay upto uint256
336 | // because they are lesser than 2^256 - 1
337 | let uint256_max = BigInt::parse_bytes(b"2", 10).unwrap().pow(256) - BigInt::one();
338 | assert_eq!(
339 | uint256_max,
340 | BigInt::parse_bytes(
341 | b"115792089237316195423570985008687907853269984665640564039457584007913129639935",
342 | 10
343 | )
344 | .unwrap()
345 | );
346 | }
347 |
348 | #[test]
349 | fn can_find_min_of_int256() {
350 | let int_256_min = BigInt::parse_bytes(b"2", 10).unwrap().pow(255).neg();
351 | assert_eq!(
352 | int_256_min,
353 | BigInt::parse_bytes(
354 | b"-57896044618658097711785492504343953926634992332820282019728792003956564819968",
355 | 10
356 | )
357 | .unwrap()
358 | );
359 | }
360 |
361 | #[test]
362 | fn can_find_max_of_int256() {
363 | let int_256_max = BigInt::parse_bytes(b"2", 10).unwrap().pow(255) - BigInt::one();
364 | assert_eq!(
365 | int_256_max,
366 | BigInt::parse_bytes(
367 | b"57896044618658097711785492504343953926634992332820282019728792003956564819967",
368 | 10
369 | )
370 | .unwrap()
371 | );
372 | }
373 |
374 | /*
375 | Tests that our helper methods work which will ensure that min and max value can be calculated
376 | for every bit range from 0 to 256 .
377 | */
378 |
379 | #[test]
380 | fn helper_method_can_find_max_of_uint256() {
381 | let uint256_max = find_uint_max(256);
382 | assert_eq!(
383 | uint256_max,
384 | BigInt::parse_bytes(
385 | b"115792089237316195423570985008687907853269984665640564039457584007913129639935",
386 | 10
387 | )
388 | .unwrap()
389 | );
390 | }
391 |
392 | #[test]
393 | fn helper_method_can_find_min_of_int256() {
394 | let int_256_min = find_int_min(256);
395 | assert_eq!(
396 | int_256_min,
397 | BigInt::parse_bytes(
398 | b"-57896044618658097711785492504343953926634992332820282019728792003956564819968",
399 | 10
400 | )
401 | .unwrap()
402 | );
403 | }
404 |
405 | #[test]
406 | fn helper_method_can_find_max_of_int256() {
407 | let int_256_max = find_int_max(256);
408 | assert_eq!(
409 | int_256_max,
410 | BigInt::parse_bytes(
411 | b"57896044618658097711785492504343953926634992332820282019728792003956564819967",
412 | 10
413 | )
414 | .unwrap()
415 | );
416 | }
417 |
418 | #[test]
419 | fn helper_method_can_find_range_for_int176() {
420 | let actual_range = get_range_for_type_string("int176").unwrap();
421 | let expected_range = SolidityNumberRange {
422 | min_val: BigInt::parse_bytes(
423 | b"-47890485652059026823698344598447161988085597568237568",
424 | 10,
425 | )
426 | .unwrap(),
427 | max_val: BigInt::parse_bytes(
428 | b"47890485652059026823698344598447161988085597568237567",
429 | 10,
430 | )
431 | .unwrap(),
432 | };
433 | assert_eq!(actual_range, expected_range);
434 | }
435 |
436 | #[test]
437 | fn helper_method_can_find_range_for_int248() {
438 | let actual_range = get_range_for_type_string("int248").unwrap();
439 | let expected_range = SolidityNumberRange {
440 | min_val: BigInt::parse_bytes(
441 | b"-226156424291633194186662080095093570025917938800079226639565593765455331328",
442 | 10,
443 | )
444 | .unwrap(),
445 | max_val: BigInt::parse_bytes(
446 | b"226156424291633194186662080095093570025917938800079226639565593765455331327",
447 | 10,
448 | )
449 | .unwrap(),
450 | };
451 | assert_eq!(actual_range, expected_range);
452 | }
453 |
454 | #[test]
455 | fn helper_method_can_find_range_for_int24() {
456 | let actual_range = get_range_for_type_string("int24").unwrap();
457 | let expected_range = SolidityNumberRange {
458 | min_val: BigInt::parse_bytes(b"-8388608", 10).unwrap(),
459 | max_val: BigInt::parse_bytes(b"8388607", 10).unwrap(),
460 | };
461 | assert_eq!(actual_range, expected_range);
462 | }
463 |
464 | #[test]
465 | fn helper_method_can_find_range_for_uint144() {
466 | let actual_range = get_range_for_type_string("uint144").unwrap();
467 | let expected_range = SolidityNumberRange {
468 | min_val: BigInt::ZERO,
469 | max_val: BigInt::parse_bytes(b"22300745198530623141535718272648361505980415", 10)
470 | .unwrap(),
471 | };
472 | assert_eq!(actual_range, expected_range);
473 | }
474 |
475 | #[test]
476 | fn helper_method_can_find_range_for_uint232() {
477 | let actual_range = get_range_for_type_string("uint232").unwrap();
478 | let expected_range = SolidityNumberRange {
479 | min_val: BigInt::ZERO,
480 | max_val: BigInt::parse_bytes(
481 | b"6901746346790563787434755862277025452451108972170386555162524223799295",
482 | 10,
483 | )
484 | .unwrap(),
485 | };
486 | assert_eq!(actual_range, expected_range);
487 | }
488 |
489 | #[test]
490 | fn helper_method_can_find_range_for_uint256() {
491 | let actual_range = get_range_for_type_string("uint256").unwrap();
492 | let expected_range = SolidityNumberRange {
493 | min_val: BigInt::ZERO,
494 | max_val: BigInt::parse_bytes(
495 | b"115792089237316195423570985008687907853269984665640564039457584007913129639935",
496 | 10,
497 | )
498 | .unwrap(),
499 | };
500 | assert_eq!(actual_range, expected_range);
501 | }
502 |
503 | #[test]
504 | fn helper_method_can_find_range_for_uint8() {
505 | let actual_range = get_range_for_type_string("uint8").unwrap();
506 | let expected_range = SolidityNumberRange {
507 | min_val: BigInt::ZERO,
508 | max_val: BigInt::parse_bytes(b"255", 10).unwrap(),
509 | };
510 | assert_eq!(actual_range, expected_range);
511 | }
512 |
513 | #[test]
514 | fn does_operation_make_sense_lhs_uint8_part1() {
515 | let does_not_make_sense =
516 | !does_operation_make_sense_with_lhs_value("256", ">=", "uint8").unwrap();
517 | assert!(does_not_make_sense);
518 | }
519 |
520 | #[test]
521 | fn does_operation_make_sense_rhs_uint8_part1() {
522 | let does_make_sense =
523 | does_operation_make_sense_with_rhs_value("uint8", "<", "255").unwrap();
524 | assert!(does_make_sense);
525 | }
526 |
527 | #[test]
528 | fn does_operation_make_sense_lhs_uint8_part2() {
529 | let does_not_make_sense =
530 | !does_operation_make_sense_with_lhs_value("255", ">=", "uint8").unwrap();
531 | assert!(does_not_make_sense);
532 | }
533 |
534 | #[test]
535 | fn does_operation_make_sense_lhs_uint8_part3() {
536 | let does_make_sense =
537 | does_operation_make_sense_with_lhs_value("245", ">=", "uint8").unwrap();
538 | assert!(does_make_sense);
539 | }
540 |
541 | #[test]
542 | fn does_operation_make_sense_rhs_uint8_part2() {
543 | let does_make_sense =
544 | does_operation_make_sense_with_rhs_value("uint8", "<", "89").unwrap();
545 | assert!(does_make_sense);
546 | }
547 |
548 | #[test]
549 | fn does_operation_make_sense_rhs_uint256_part3() {
550 | let does_make_sense =
551 | does_operation_make_sense_with_rhs_value("uint256", ">", "0").unwrap();
552 | assert!(does_make_sense);
553 | }
554 |
555 | #[test]
556 | fn does_operation_make_sense_rhs_uint256_part4() {
557 | let does_not_make_sense =
558 | !does_operation_make_sense_with_rhs_value("uint256", ">=", "0").unwrap();
559 | assert!(does_not_make_sense);
560 | }
561 |
562 | #[test]
563 | fn does_operation_make_sense_rhs_uint72_part5() {
564 | let does_not_make_sense =
565 | !does_operation_make_sense_with_rhs_value("uint72", "<", "0").unwrap();
566 | assert!(does_not_make_sense);
567 | }
568 |
569 | #[test]
570 | fn does_operation_make_sense_rhs_uint8_part6() {
571 | let does_not_make_sense =
572 | !does_operation_make_sense_with_rhs_value("uint8", ">", "258").unwrap();
573 | assert!(does_not_make_sense);
574 | }
575 | }
576 | }
577 |
```
--------------------------------------------------------------------------------
/aderyn_core/src/ast/ast_nodes.rs:
--------------------------------------------------------------------------------
```rust
1 | use super::{
2 | macros::{ast_node, ast_node_no_partial_eq, expr_node, node_group, stmt_node},
3 | *,
4 | };
5 | use std::collections::{BTreeMap, HashMap};
6 |
7 | use serde::{Deserialize, Serialize};
8 |
9 | node_group! {
10 | SourceUnitNode;
11 |
12 | ContractDefinition,
13 | EnumDefinition,
14 | ErrorDefinition,
15 | EventDefinition,
16 | FunctionDefinition,
17 | ImportDirective,
18 | PragmaDirective,
19 | StructDefinition,
20 | UserDefinedValueTypeDefinition,
21 | UsingForDirective,
22 | VariableDeclaration,
23 | }
24 |
25 | node_group! {
26 | Expression;
27 |
28 | Assignment,
29 | BinaryOperation,
30 | Conditional,
31 | ElementaryTypeNameExpression,
32 | FunctionCall,
33 | FunctionCallOptions,
34 | Identifier,
35 | IndexAccess,
36 | IndexRangeAccess,
37 | Literal,
38 | MemberAccess,
39 | NewExpression,
40 | TupleExpression,
41 | UnaryOperation,
42 | }
43 |
44 | node_group! {
45 | Statement;
46 |
47 | Block,
48 | Break,
49 | Continue,
50 | DoWhileStatement,
51 | EmitStatement,
52 | ExpressionStatement,
53 | ForStatement,
54 | IfStatement,
55 | InlineAssembly,
56 | PlaceholderStatement,
57 | Return,
58 | RevertStatement,
59 | TryStatement,
60 | UncheckedBlock,
61 | VariableDeclarationStatement,
62 | WhileStatement,
63 | }
64 |
65 | node_group! {
66 | ContractDefinitionNode;
67 |
68 | EnumDefinition,
69 | ErrorDefinition,
70 | EventDefinition,
71 | FunctionDefinition,
72 | ModifierDefinition,
73 | StructDefinition,
74 | UserDefinedValueTypeDefinition,
75 | UsingForDirective,
76 | VariableDeclaration,
77 | }
78 |
79 | #[derive(Clone, Debug, Eq, Serialize, PartialEq, Hash)]
80 | pub enum TypeName {
81 | ArrayTypeName(ArrayTypeName),
82 | ElementaryTypeName(ElementaryTypeName),
83 | FunctionTypeName(FunctionTypeName),
84 | Mapping(Mapping),
85 | /// A string representing the type name.
86 | ///
87 | /// This variant applies to older compiler versions.
88 | Raw(String),
89 | UserDefinedTypeName(UserDefinedTypeName),
90 | }
91 |
92 | impl<'de> Deserialize<'de> for TypeName {
93 | fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
94 | let json = serde_json::Value::deserialize(deserializer)?;
95 | let node_type = json.get("nodeType");
96 |
97 | if node_type.is_none() {
98 | return Ok(TypeName::Raw(json.to_string()));
99 | }
100 |
101 | let type_name = node_type.unwrap().as_str().unwrap();
102 |
103 | match type_name {
104 | "FunctionTypeName" => {
105 | Ok(TypeName::FunctionTypeName(serde_json::from_value(json).unwrap()))
106 | }
107 | "ArrayTypeName" => Ok(TypeName::ArrayTypeName(serde_json::from_value(json).unwrap())),
108 | "Mapping" => Ok(TypeName::Mapping(serde_json::from_value(json).unwrap())),
109 | "UserDefinedTypeName" => {
110 | Ok(TypeName::UserDefinedTypeName(serde_json::from_value(json).unwrap()))
111 | }
112 | "ElementaryTypeName" => {
113 | Ok(TypeName::ElementaryTypeName(serde_json::from_value(json).unwrap()))
114 | }
115 | _ => panic!("Unrecognized type name {type_name}"),
116 | }
117 | }
118 | }
119 |
120 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
121 | #[serde(tag = "nodeType")]
122 | pub enum UserDefinedTypeNameOrIdentifierPath {
123 | UserDefinedTypeName(UserDefinedTypeName),
124 | IdentifierPath(IdentifierPath),
125 | }
126 |
127 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
128 | #[serde(tag = "nodeType")]
129 | pub enum ExpressionOrVariableDeclarationStatement {
130 | ExpressionStatement(ExpressionStatement),
131 | VariableDeclarationStatement(VariableDeclarationStatement),
132 | }
133 |
134 | impl ExpressionOrVariableDeclarationStatement {
135 | pub fn get_node_id(&self) -> Option<NodeID> {
136 | match self {
137 | ExpressionOrVariableDeclarationStatement::ExpressionStatement(expression) => {
138 | Some(expression.id)
139 | }
140 | ExpressionOrVariableDeclarationStatement::VariableDeclarationStatement(vd_stmnt) => {
141 | Some(vd_stmnt.id)
142 | }
143 | }
144 | }
145 | }
146 |
147 | ast_node!(
148 | #[derive(Hash)]
149 | struct Block {
150 | statements: Vec<Statement>,
151 | }
152 | );
153 |
154 | stmt_node!(
155 | #[derive(Hash)]
156 | struct UncheckedBlock {
157 | statements: Vec<Statement>,
158 | }
159 | );
160 |
161 | #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
162 | #[serde(rename_all = "lowercase")]
163 | pub enum ContractKind {
164 | Contract,
165 | Interface,
166 | Library,
167 | }
168 |
169 | ast_node!(
170 | #[derive(Hash)]
171 | struct InheritanceSpecifier {
172 | base_name: UserDefinedTypeNameOrIdentifierPath,
173 | arguments: Option<Vec<Expression>>,
174 | }
175 | );
176 |
177 | ast_node!(
178 | #[derive(Hash)]
179 | struct ContractDefinition {
180 | name: String,
181 | name_location: Option<String>,
182 | documentation: Option<Documentation>,
183 | #[serde(rename = "contractKind")]
184 | kind: ContractKind,
185 | #[serde(default, rename = "abstract")]
186 | is_abstract: bool,
187 | base_contracts: Vec<InheritanceSpecifier>,
188 | canonical_name: Option<String>,
189 | contract_dependencies: Vec<NodeID>,
190 | used_errors: Option<Vec<NodeID>>,
191 | used_events: Option<Vec<usize>>,
192 | #[serde(default, rename = "internalFunctionIDs")]
193 | internal_function_ids: BTreeMap<String, usize>,
194 | nodes: Vec<ContractDefinitionNode>,
195 | scope: NodeID,
196 | fully_implemented: bool,
197 | linearized_base_contracts: Vec<NodeID>,
198 | }
199 | );
200 |
201 | #[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, Hash)]
202 | #[serde(untagged)]
203 | pub enum Documentation {
204 | String(Option<String>),
205 | Structured(Option<StructuredDocumentation>),
206 | }
207 |
208 | ast_node!(
209 | #[derive(Hash)]
210 | struct StructuredDocumentation {
211 | text: String,
212 | }
213 | );
214 |
215 | ast_node!(
216 | #[derive(Hash)]
217 | struct EnumValue {
218 | name: String,
219 | name_location: Option<String>,
220 | }
221 | );
222 |
223 | ast_node!(
224 | #[derive(Hash)]
225 | struct EnumDefinition {
226 | name: String,
227 | name_location: Option<String>,
228 | members: Vec<EnumValue>,
229 | canonical_name: Option<String>,
230 | }
231 | );
232 |
233 | ast_node!(
234 | #[derive(Hash)]
235 | struct ErrorDefinition {
236 | documentation: Option<Documentation>,
237 | error_selector: Option<String>,
238 | name: String,
239 | name_location: Option<String>,
240 | parameters: ParameterList,
241 | }
242 | );
243 |
244 | ast_node!(
245 | #[derive(Hash)]
246 | struct EventDefinition {
247 | anonymous: bool,
248 | documentation: Option<Documentation>,
249 | name: String,
250 | name_location: Option<String>,
251 | parameters: ParameterList,
252 | event_selector: Option<String>,
253 | }
254 | );
255 |
256 | expr_node!(
257 | #[derive(Hash)]
258 | struct UnaryOperation {
259 | operator: String,
260 | /// Whether the unary operator is before or after the expression (e.g. `x++` vs. `++x`)
261 | prefix: bool,
262 | sub_expression: Box<Expression>,
263 | }
264 | );
265 |
266 | expr_node!(
267 | #[derive(Hash)]
268 | struct BinaryOperation {
269 | common_type: TypeDescriptions,
270 | left_expression: Box<Expression>,
271 | right_expression: Box<Expression>,
272 | operator: String,
273 | }
274 | );
275 |
276 | expr_node!(
277 | #[derive(Hash)]
278 | struct Conditional {
279 | condition: Box<Expression>,
280 | true_expression: Box<Expression>,
281 | false_expression: Box<Expression>,
282 | }
283 | );
284 |
285 | expr_node!(
286 | #[derive(Hash)]
287 | struct Assignment {
288 | left_hand_side: Box<Expression>,
289 | right_hand_side: Box<Expression>,
290 | operator: String,
291 | }
292 | );
293 |
294 | expr_node!(
295 | #[derive(Hash)]
296 | struct FunctionCall {
297 | kind: FunctionCallKind,
298 | #[serde(default)]
299 | try_call: bool,
300 | names: Vec<String>,
301 | arguments: Vec<Expression>,
302 | expression: Box<Expression>,
303 | }
304 | );
305 |
306 | #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
307 | #[serde(rename_all = "camelCase")]
308 | pub enum FunctionCallKind {
309 | FunctionCall,
310 | TypeConversion,
311 | StructConstructorCall,
312 | }
313 |
314 | expr_node!(
315 | #[derive(Hash)]
316 | struct FunctionCallOptions {
317 | names: Vec<String>,
318 | options: Vec<Expression>,
319 | arguments: Option<Vec<Expression>>,
320 | expression: Box<Expression>,
321 | }
322 | );
323 |
324 | expr_node!(
325 | #[derive(Hash)]
326 | struct NewExpression {
327 | type_name: TypeName,
328 | }
329 | );
330 |
331 | expr_node!(
332 | #[derive(Hash)]
333 | struct IndexAccess {
334 | base_expression: Box<Expression>,
335 | index_expression: Option<Box<Expression>>,
336 | }
337 | );
338 |
339 | expr_node!(
340 | #[derive(Hash)]
341 | struct IndexRangeAccess {
342 | base_expression: Box<Expression>,
343 | start_expression: Option<Box<Expression>>,
344 | end_expression: Option<Box<Expression>>,
345 | }
346 | );
347 |
348 | expr_node!(
349 | #[derive(Hash)]
350 | struct MemberAccess {
351 | member_name: String,
352 | expression: Box<Expression>,
353 | referenced_declaration: Option<NodeID>,
354 | }
355 | );
356 |
357 | expr_node!(
358 | #[derive(Hash)]
359 | struct ElementaryTypeNameExpression {
360 | type_name: TypeName,
361 | }
362 | );
363 |
364 | expr_node!(
365 | #[derive(Hash)]
366 | struct TupleExpression {
367 | components: Vec<Option<Expression>>,
368 | is_inline_array: bool,
369 | }
370 | );
371 |
372 | #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
373 | #[serde(rename_all = "camelCase")]
374 | pub enum FunctionKind {
375 | Constructor,
376 | Function,
377 | Receive,
378 | Fallback,
379 | FreeFunction,
380 | }
381 |
382 | ast_node!(
383 | #[derive(Hash)]
384 | struct ParameterList {
385 | parameters: Vec<VariableDeclaration>,
386 | }
387 | );
388 |
389 | ast_node!(
390 | #[derive(Hash)]
391 | struct OverrideSpecifier {
392 | overrides: Vec<UserDefinedTypeNameOrIdentifierPath>,
393 | }
394 | );
395 |
396 | ast_node!(
397 | #[derive(Hash)]
398 | struct FunctionDefinition {
399 | base_functions: Option<Vec<NodeID>>,
400 | body: Option<Block>,
401 | documentation: Option<Documentation>,
402 | function_selector: Option<String>,
403 | implemented: bool,
404 | /// The kind of function this node defines. Only valid for Solidity versions 0.5.x and
405 | /// above.
406 | ///
407 | /// For cross-version compatibility use [`FunctionDefinition::kind()`].
408 | kind: Option<FunctionKind>,
409 | #[serde(default)]
410 | /// For cross-version compatibility use [`FunctionDefinition::state_mutability()`].
411 | state_mutability: Option<StateMutability>,
412 | #[serde(default, rename = "virtual")]
413 | is_virtual: bool,
414 | /// Whether or not this function is the constructor. Only valid for Solidity versions below
415 | /// 0.5.x.
416 | ///
417 | /// After 0.5.x you must use `kind`. For cross-version compatibility use
418 | /// [`FunctionDefinition::kind()`].
419 | #[serde(default)]
420 | is_constructor: bool,
421 | /// Whether or not this function is constant (view or pure). Only valid for Solidity
422 | /// versions below 0.5.x.
423 | ///
424 | /// After 0.5.x you must use `state_mutability`. For cross-version compatibility use
425 | /// [`FunctionDefinition::state_mutability()`].
426 | #[serde(default)]
427 | is_declared_const: bool,
428 | /// Whether or not this function is payable. Only valid for Solidity versions below
429 | /// 0.5.x.
430 | ///
431 | /// After 0.5.x you must use `state_mutability`. For cross-version compatibility use
432 | /// [`FunctionDefinition::state_mutability()`].
433 | #[serde(default)]
434 | is_payable: bool,
435 | modifiers: Vec<ModifierInvocation>,
436 | name: String,
437 | name_location: Option<String>,
438 | overrides: Option<OverrideSpecifier>,
439 | parameters: ParameterList,
440 | return_parameters: ParameterList,
441 | scope: NodeID,
442 | super_function: Option<NodeID>,
443 | visibility: Visibility,
444 | }
445 | );
446 |
447 | ast_node_no_partial_eq!(
448 | struct Identifier {
449 | argument_types: Option<Vec<TypeDescriptions>>,
450 | name: String,
451 | overloaded_declarations: Vec<NodeID>,
452 | referenced_declaration: Option<NodeID>,
453 | type_descriptions: TypeDescriptions,
454 | }
455 | );
456 |
457 | ast_node_no_partial_eq!(
458 | struct IdentifierPath {
459 | name: String,
460 | referenced_declaration: i64,
461 | }
462 | );
463 |
464 | #[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, Hash)]
465 | #[serde(rename_all = "camelCase")]
466 | pub struct SymbolAlias {
467 | pub foreign: Identifier,
468 | pub local: Option<String>,
469 | pub name_location: Option<String>,
470 | }
471 |
472 | ast_node!(
473 | #[derive(Hash)]
474 | struct ImportDirective {
475 | file: String,
476 | source_unit: NodeID,
477 | scope: NodeID,
478 | absolute_path: Option<String>,
479 | unit_alias: String,
480 | name_location: Option<String>,
481 | symbol_aliases: Vec<SymbolAlias>,
482 | }
483 | );
484 |
485 | #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
486 | #[serde(rename_all = "camelCase")]
487 | pub enum LiteralKind {
488 | Bool,
489 | Number,
490 | String,
491 | HexString,
492 | Address,
493 | UnicodeString,
494 | }
495 |
496 | expr_node!(
497 | #[derive(Hash)]
498 | struct Literal {
499 | hex_value: String,
500 | value: Option<String>,
501 | subdenomination: Option<String>,
502 | kind: LiteralKind,
503 | }
504 | );
505 |
506 | ast_node!(
507 | #[derive(Hash)]
508 | struct ModifierDefinition {
509 | body: Option<Block>,
510 | base_modifiers: Option<Vec<usize>>,
511 | overrides: Option<OverrideSpecifier>,
512 | documentation: Option<Documentation>,
513 | name: String,
514 | name_location: Option<String>,
515 | parameters: ParameterList,
516 | #[serde(default, rename = "virtual")]
517 | is_virtual: bool,
518 | visibility: Visibility,
519 | }
520 | );
521 |
522 | #[derive(Clone, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
523 | #[serde(rename_all = "camelCase")]
524 | pub enum ModifierInvocationKind {
525 | ModifierInvocation,
526 | BaseConstructorSpecifier,
527 | }
528 |
529 | ast_node!(
530 | #[derive(Hash)]
531 | struct ModifierInvocation {
532 | arguments: Option<Vec<Expression>>,
533 | modifier_name: IdentifierOrIdentifierPath,
534 | kind: Option<ModifierInvocationKind>,
535 | }
536 | );
537 |
538 | #[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, Hash)]
539 | #[serde(tag = "nodeType")]
540 | pub enum IdentifierOrIdentifierPath {
541 | Identifier(Identifier),
542 | IdentifierPath(IdentifierPath),
543 | }
544 |
545 | ast_node!(
546 | #[derive(Hash)]
547 | struct PragmaDirective {
548 | literals: Vec<String>,
549 | }
550 | );
551 |
552 | ast_node!(
553 | struct SourceUnit {
554 | license: Option<String>,
555 | nodes: Vec<SourceUnitNode>,
556 | exported_symbols: Option<HashMap<String, Vec<NodeID>>>,
557 | absolute_path: Option<String>,
558 |
559 | #[serde(skip_serializing)]
560 | source: Option<String>,
561 | }
562 | );
563 |
564 | stmt_node!(
565 | #[derive(Hash)]
566 | struct ExpressionStatement {
567 | expression: Expression,
568 | }
569 | );
570 |
571 | stmt_node!(
572 | #[derive(Hash)]
573 | struct VariableDeclarationStatement {
574 | assignments: Vec<Option<NodeID>>,
575 | declarations: Vec<Option<VariableDeclaration>>,
576 | initial_value: Option<Expression>,
577 | }
578 | );
579 |
580 | #[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, Hash)]
581 | #[serde(untagged)]
582 | pub enum BlockOrStatement {
583 | Block(Box<Block>),
584 | Statement(Box<Statement>),
585 | }
586 |
587 | stmt_node!(
588 | #[derive(Hash)]
589 | struct IfStatement {
590 | condition: Expression,
591 | true_body: BlockOrStatement,
592 | false_body: Option<BlockOrStatement>,
593 | }
594 | );
595 |
596 | stmt_node!(
597 | #[derive(Hash)]
598 | struct ForStatement {
599 | initialization_expression: Option<Box<ExpressionOrVariableDeclarationStatement>>,
600 | condition: Option<Expression>,
601 | loop_expression: Option<Box<ExpressionStatement>>,
602 | body: BlockOrStatement,
603 | }
604 | );
605 |
606 | stmt_node!(
607 | #[derive(Hash)]
608 | struct DoWhileStatement {
609 | body: Block,
610 | condition: Expression,
611 | }
612 | );
613 |
614 | stmt_node!(
615 | #[derive(Hash)]
616 | struct EmitStatement {
617 | event_call: FunctionCall,
618 | }
619 | );
620 |
621 | stmt_node!(
622 | #[derive(Hash)]
623 | struct TryStatement {
624 | clauses: Vec<TryCatchClause>,
625 | external_call: FunctionCall,
626 | }
627 | );
628 |
629 | stmt_node!(
630 | #[derive(Hash)]
631 | struct RevertStatement {
632 | error_call: FunctionCall,
633 | }
634 | );
635 |
636 | ast_node!(
637 | #[derive(Hash)]
638 | struct TryCatchClause {
639 | block: Block,
640 | error_name: String,
641 | parameters: Option<ParameterList>,
642 | }
643 | );
644 |
645 | stmt_node!(
646 | #[derive(Hash)]
647 | struct Return {
648 | function_return_parameters: Option<NodeID>, /* When returning in a modifier, this can be
649 | * none */
650 | expression: Option<Expression>,
651 | }
652 | );
653 |
654 | ast_node!(
655 | #[derive(Hash)]
656 | struct InlineAssembly {
657 | #[serde(rename = "AST")]
658 | ast: Option<YulBlock>,
659 | evm_version: Option<String>,
660 | external_references: Vec<ExternalReference>,
661 | operations: Option<String>,
662 | }
663 | );
664 |
665 | stmt_node!(
666 | #[derive(Hash)]
667 | struct Break {}
668 | );
669 |
670 | stmt_node!(
671 | #[derive(Hash)]
672 | struct Continue {}
673 | );
674 |
675 | stmt_node!(
676 | #[derive(Hash)]
677 | struct PlaceholderStatement {}
678 | );
679 |
680 | stmt_node!(
681 | #[derive(Hash)]
682 | struct WhileStatement {
683 | condition: Expression,
684 | body: BlockOrStatement,
685 | }
686 | );
687 |
688 | ast_node!(
689 | #[derive(Hash)]
690 | struct StructDefinition {
691 | name: String,
692 | name_location: Option<String>,
693 | visibility: Visibility,
694 | members: Vec<VariableDeclaration>,
695 | scope: NodeID,
696 | canonical_name: Option<String>,
697 | }
698 | );
699 |
700 | #[derive(Clone, Debug, Deserialize, Eq, Serialize, PartialEq, Hash)]
701 | #[serde(rename_all = "camelCase")]
702 | pub struct TypeDescriptions {
703 | pub type_identifier: Option<String>,
704 | pub type_string: Option<String>,
705 | }
706 |
707 | ast_node_no_partial_eq!(
708 | struct ElementaryTypeName {
709 | state_mutability: Option<StateMutability>,
710 | name: String,
711 | type_descriptions: TypeDescriptions,
712 | }
713 | );
714 |
715 | ast_node_no_partial_eq!(
716 | struct UserDefinedTypeName {
717 | path_node: Option<IdentifierPath>,
718 | referenced_declaration: NodeID,
719 | name: Option<String>,
720 | type_descriptions: TypeDescriptions,
721 | contract_scope: Option<String>,
722 | }
723 | );
724 |
725 | ast_node!(
726 | #[derive(Hash)]
727 | struct FunctionTypeName {
728 | visibility: Visibility,
729 | state_mutability: StateMutability,
730 | parameter_types: ParameterList,
731 | return_parameter_types: ParameterList,
732 | type_descriptions: TypeDescriptions,
733 | }
734 | );
735 |
736 | ast_node!(
737 | #[derive(Hash)]
738 | struct ArrayTypeName {
739 | base_type: Box<TypeName>,
740 | length: Box<Option<Expression>>,
741 | type_descriptions: TypeDescriptions,
742 | }
743 | );
744 |
745 | ast_node!(
746 | #[derive(Hash)]
747 | struct Mapping {
748 | key_type: Box<TypeName>,
749 | value_type: Box<TypeName>,
750 | type_descriptions: TypeDescriptions,
751 | }
752 | );
753 |
754 | ast_node!(
755 | #[derive(Hash)]
756 | struct UserDefinedValueTypeDefinition {
757 | underlying_type: TypeName,
758 | name: String,
759 | name_location: Option<String>,
760 | canonical_name: Option<String>,
761 | }
762 | );
763 |
764 | ast_node!(
765 | #[derive(Hash)]
766 | struct UsingForDirective {
767 | function_list: Option<Vec<UsingForFunctionItem>>,
768 | #[serde(default)]
769 | global: bool,
770 | library_name: Option<UserDefinedTypeNameOrIdentifierPath>,
771 | type_name: Option<TypeName>,
772 | }
773 | );
774 |
775 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
776 | #[serde(untagged)]
777 | pub enum UsingForFunctionItem {
778 | Function(FunctionIdentifierPath),
779 | OverloadedOperator(OverloadedOperator),
780 | }
781 |
782 | /// A wrapper around [IdentifierPath] for the [UsingForDirective].
783 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
784 | pub struct FunctionIdentifierPath {
785 | pub function: IdentifierPath,
786 | }
787 |
788 | #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]
789 | pub struct OverloadedOperator {
790 | pub definition: IdentifierPath,
791 | pub operator: String,
792 | }
793 |
794 | #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
795 | #[serde(rename_all = "lowercase")]
796 | pub enum Mutability {
797 | Immutable,
798 | Mutable,
799 | Constant,
800 | }
801 |
802 | #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
803 | #[serde(rename_all = "lowercase")]
804 | pub enum StateMutability {
805 | NonPayable,
806 | Payable,
807 | View,
808 | Pure,
809 | }
810 |
811 | #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
812 | #[serde(rename_all = "lowercase")]
813 | pub enum Visibility {
814 | Public,
815 | Private,
816 | Internal,
817 | External,
818 | }
819 |
820 | #[derive(Clone, Copy, Debug, Deserialize, Serialize, PartialEq, PartialOrd, Eq, Ord, Hash)]
821 | #[serde(rename_all = "lowercase")]
822 | pub enum StorageLocation {
823 | Default,
824 | Memory,
825 | Calldata,
826 | Storage,
827 | Transient,
828 | }
829 |
830 | ast_node!(
831 | #[derive(Hash)]
832 | struct VariableDeclaration {
833 | base_functions: Option<Vec<NodeID>>,
834 | /// Marks whether or not the variable is a constant before Solidity 0.7.x.
835 | ///
836 | /// After 0.7.x you must use `mutability`. For cross-version compatibility use
837 | /// [`VariableDeclaration::mutability()`].
838 | #[serde(default)]
839 | constant: bool,
840 | documentation: Option<Documentation>,
841 | function_selector: Option<String>,
842 | indexed: Option<bool>,
843 | /// Marks the variable's mutability from Solidity 0.7.x onwards.
844 | /// For cross-version compatibility use [`VariableDeclaration::mutability()`].
845 | #[serde(default)]
846 | mutability: Option<Mutability>,
847 | name: String,
848 | name_location: Option<String>,
849 | overrides: Option<OverrideSpecifier>,
850 | scope: NodeID,
851 | /// Marks whether or not the variable is a state variable before Solidity 0.7.x.
852 | ///
853 | /// After 0.7.x you must use `mutability`. For cross-version compatibility use
854 | /// [`VariableDeclaration::mutability()`].
855 | #[serde(default)]
856 | state_variable: bool,
857 | storage_location: StorageLocation,
858 | type_descriptions: TypeDescriptions,
859 | type_name: Option<TypeName>,
860 | value: Option<Expression>,
861 | visibility: Visibility,
862 | }
863 | );
864 |
```