Coder Social home page Coder Social logo

crytic / fuzz-utils Goto Github PK

View Code? Open in Web Editor NEW
82.0 3.0 3.0 2.28 MB

A tool to automatically generate Foundry unit test cases from Echidna and Medusa failed properties

License: GNU Affero General Public License v3.0

Python 46.12% Solidity 53.11% Makefile 0.77%

fuzz-utils's Introduction

Slither Static Analysis Framework Logo

Automated utility tooling for smart contract fuzzers

fuzz-utils is a set of Python tools that aim to improve the developer experience when using smart contract fuzzing. The tools include:

  • automatically generate unit tests from Echidna and Medusa failed properties, using the generated reproducer files.
  • automatically generate a Echidna/Medusa compatible fuzzing harness.

fuzz-utils uses Slither for determining types and jinja2 for generating the test files using string templates.

Disclaimer: Please note that fuzz-utils is under development. Currently, not all Solidity types are supported and some types (like bytes*, and string) might be improperly decoded from the corpora call sequences. We are investigating a better corpus format that will ease the creation of unit tests.

Features

fuzz-utils provides support for:

  • ✔️ Generating Foundry unit tests from the fuzzer corpus of single entry point fuzzing harnesses.
  • ✔️ Generating fuzzing harnesses, Actor contracts, and templated attack contracts to ease fuzzing setup.
  • ✔️ Supports Medusa and Echidna corpora
  • ✔️ Test generation supports Solidity types: bool,uint*, int*, address, struct, enum, single-dimensional fixed-size arrays and dynamic arrays, multi-dimensional fixed-size arrays.

Multi-dimensional dynamic arrays, function pointers, and other more complex types are in the works, but are currently not supported.

Installation and pre-requisites

To install fuzz-utils:

pip install fuzz-utils

These commands will install all the Python libraries and tools required to run fuzz-utils. However, it won't install Echidna or Medusa, so you will need to download and install the latest version yourself from its official releases (Echidna, Medusa).

Tools

The available tool commands are:

  • init - Initializes a configuration file
  • generate - generates unit tests from a corpus
  • template - generates a fuzzing harness

Generating unit tests

The generate command is used to generate Foundry unit tests from Echidna or Medusa corpus call sequences.

Command-line options:

  • compilation_path: The path to the Solidity file or Foundry directory. By default .
  • -cd/--corpus-dir path_to_corpus_dir: The path to the corpus directory relative to the working directory. By default corpus
  • -c/--contract contract_name: The name of the target contract. If the compilation path only contains one contract the target will be automatically derived.
  • -td/--test-directory path_to_test_directory: The path to the test directory relative to the working directory. By default test
  • -i/--inheritance-path relative_path_to_contract: The relative path from the test directory to the contract (used for overriding inheritance). If this configuration option is not provided the inheritance path will be automatically derived.
  • -f/--fuzzer fuzzer_name: The name of the fuzzer, currently supported: echidna and medusa. By default medusa
  • --named-inputs: Includes function input names when making calls. By defaultfalse
  • --config: Path to the fuzz-utils config JSON file. Empty by default.
  • --all-sequences: Include all corpus sequences when generating unit tests. By default false

Example

In order to generate a test file for the BasicTypes.sol contract, based on the Echidna corpus reproducers for this contract (corpus-basic), we need to cd into the tests/test_data directory which contains the Foundry project and run the command:

fuzz-utils generate ./src/BasicTypes.sol --corpus-dir echidna-corpora/corpus-basic --contract "BasicTypes" --fuzzer echidna

Running this command should generate a BasicTypes_Echidna_Test.sol file in the test directory of the Foundry project.

Generating fuzzing harnesses

The template command is used to generate a fuzzing harness. The harness can include multiple Actor contracts which are used as proxies for user actions, as well as attack contracts which can be selected from a set of premade contracts that perform certain common attack scenarios.

Command-line options:

  • compilation_path: The path to the Solidity file or Foundry directory
  • -n/--name name: str: The name of the fuzzing harness. By default DefaultHarness
  • -c/--contracts target_contracts: list: The name of the target contract. Empty by default.
  • -o/--output-dir output_directory: str: Output directory name. By default fuzzing
  • --config: Path to the fuzz-utils config JSON file
  • --mode: The strategy to use when generating the harnesses. Valid options: simple, prank, actor

Generation modes The tool support three harness generation strategies:

  • simple - The fuzzing harness will be generated with all of the state-changing functions from the target contracts. All function calls are performed directly, with the harness contract as the msg.sender.
  • prank - Similar to simple mode, with the difference that function calls are made from different users by using hevm.prank(). The users can be defined in the configuration file as "actors": ["0xb4b3", "0xb0b", ...]
  • actor - Actor contracts will be generated and all harness function calls will be proxied through these contracts. The Actor contracts can be considered as users of the target contracts and the functions included in these actors can be filtered by modifier, external calls, or by payable. This allows for granular control over user capabilities.

Example

In order to generate a fuzzing harness for the TestERC20.sol contract, we need to cd into the tests/test_data/ directory which contains the Foundry project and run the command:

fuzz-utils template ./src/TestERC20.sol --name "ERC20Harness" --contracts TestERC20

Running this command should generate the directory structure in tests/test_data/test/fuzzing, which contains the fuzzing harness ERC20Harness and the Actor contract DefaultActor.

We can see that the tool has generated the DefaultActor contract which contains all the functions of our ERC20 token, and that our fuzzing harness ERC20Harness is able to call each of these functions by randomly selecting one of the deployed actors, simulating different users.

This reduces the amount of time you need to set up fuzzing harness boilerplate and let's you focus on what really matters, defining invariants and testing the system.

Utilities

Initializing a configuration file

The init command can be used to initialize a default configuration file in the project root.

Configuration file: Using the configuration file allows for more granular control than just using the command-line options. Valid configuration options are listed below:

{
    "generate": {
        "targetContract": "BasicTypes",              // The Echidna/Medusa fuzzing harness 
        "compilationPath": "./src/BasicTypes",       // Path to the file or Foundry directory
        "corpusDir": "echidna-corpora/corpus-basic", // Path to the corpus directory
        "fuzzer": "echidna",                         // `echidna` | `medusa`
        "testsDir": "./test/",                       // Path to the directory where the tests will be generated
        "inheritancePath": "../src/",                // Relative path from the testing directory to the contracts
        "namedInputs": false,                        // True | False, whether to include function input names when making calls
        "allSequences": false,                       // True | False, whether to generate tests for the entire corpus (including non-failing sequences)
    },
    "template": {
        "name": "DefaultHarness",                    // The name of the fuzzing harness that will be generated
        "targets": ["BasicTypes"],                   // The contracts to be included in the fuzzing harness
        "outputDir": "./test/fuzzing",               // The output directory where the files and directories will be saved
        "compilationPath": ".",                      // The path to the Solidity file (if single target) or Foundry directory
        "actors": [                                  // At least one actor is required. If the array is empty, the DefaultActor which wraps all of the functions from the target contracts will be generated
            {
                "name": "Default",                   // The name of the Actor contract, saved as `Actor{name}`
                "targets": ["BasicTypes"],           // The list of contracts that the Actor can interact with
                "number": 3,                         // The number of instances of this Actor that will be used in the harness
                "filters": {                         // Used to filter functions so that only functions that fulfill certain criteria are included
                    "strict": false,                 // If `true`, only functions that fulfill *all* the criteria will be included. If `false`, functions that fulfill *any* criteria will be included
                    "onlyModifiers": [],             // List of modifiers to include
                    "onlyPayable": false,            // If `true`, only `payable` functions will be included. If `false`, both payable and non-payable functions will be included
                    "onlyExternalCalls": [],         // Only include functions that make a certain external call. E.g. [`transferFrom`]
                },
            }
        ],
        "attacks": [                                 // A list of premade attack contracts to include. 
            {
                "name": "Deposit",                   // The name of the attack contract. 
                "targets": ["BasicTypes"],           // The list of contracts that the attack contract can interact with
                "number": 1,                         // The number of instances of this attack contract that will be used in the harness
                "filters": {                         // Used to filter functions so that only functions that fulfill certain criteria are included
                    "strict": false,                 // If `true`, only functions that fulfill *all* the criteria will be included. If `false`, functions that fulfill *any* criteria will be included
                    "onlyModifiers": [],             // List of modifiers to include
                    "onlyPayable": false,            // If `true`, only `payable` functions will be included. If `false`, both payable and non-payable functions will be included
                    "onlyExternalCalls": [],         // Only include functions that make a certain external call. E.g. [`transferFrom`]
                },
            }
        ],
    },
}

Contributing

For information about how to contribute to this project, check out the CONTRIBUTING guidelines.

License

fuzz-utils is licensed and distributed under the AGPLv3.

fuzz-utils's People

Contributors

tuturu-tech avatar montyly avatar 0xalpharush avatar glarregay-tob avatar gianfrancobazzani avatar

Stargazers

neko_hat avatar Erhan avatar Paul Birnbaum  avatar 蔡佳誠 Louis Tsai avatar Jiefeng Li avatar Nick Doherty avatar  avatar Talha AYDIN avatar aweNousaku avatar Arjun avatar Brandon Wong avatar blackbigswan avatar Alberto Lalanda  avatar Alex The Entreprenerd avatar Tilak Madichetti avatar  avatar Rappie avatar Suthan Somadeva avatar  avatar  avatar Tadashi avatar Pranav  avatar  avatar Giorgio Dalla avatar  avatar pwd avatar Kris O'Shea avatar Eito Miyamura avatar Gr3yD0g avatar Elyx0 avatar 0x4E33 avatar Moo avatar Camotelli avatar RT avatar Adil Kazani avatar  avatar Gregg Dent avatar Víctor Nicolás Martínez Carralero avatar gd avatar Mayckon Barbosa da Silva avatar Scoolj, Oluwajuwonlo avatar Zaryab avatar  avatar clandestine.eth avatar J. Pratt-Delzenne avatar  avatar Edoardo Carradori avatar Kishan Sudani avatar 0xjarix avatar evalir avatar Haythem Sellami avatar Alberto avatar  avatar Sandalots avatar sam bacha avatar Matt Solomon avatar sudo rm -rf --no-preserve-root / avatar Kavita B avatar  avatar  avatar H@rsh avatar Kell (K42) avatar Na3aga avatar Luigi avatar Nazgul avatar 0x0918 avatar Bisola Olasehinde avatar 0xScourgedev avatar Antonio Viggiano avatar  avatar Giovanni Di Siena avatar Jake Loo avatar Kaccatur avatar Corrino avatar Beirao avatar Mirko Pezo avatar ThreeHrSleep avatar EV_om avatar lcfr avatar Daniel Zarifpour avatar Nat Chin avatar  avatar

Watchers

 avatar  avatar Scoolj, Oluwajuwonlo avatar

fuzz-utils's Issues

[Bug-Candidate]: Parsing error when using Medusa corpus

Describe the issue:

I'm getting the following parsing error when trying to run the tool on a corpus from a Medusa run

image

and the Foundry test it creates just contains the setup function for the target contract

image

When using an Echidna corpus it gives no parsing error but creates the same Foundry test

image

I'm unsure of whether this is due to a misconfiguration on my part or an actual bug in the tool.

Code example to reproduce the issue:

This repo is the one on which the issue appeared, it uses the default Foundry template and the only thing that's been added is an invariant in the FuzzCounter contract: https://github.com/nican0r/fuzz-utils-repro

The FuzzCounter contract also includes the commands I used for running the tool along with the command I used for running Echidna. Please lmk if there's anything else I can add that might help.

Version:

0.0.1

Relevant log output:

Generating Foundry unit tests based on the Medusa reproducers...
Parsing fail on [{'call': {'from': '0x0000000000000000000000000000000000030000', 'to': '0xa647ff3c36cfab592509e13860ab8c4f28781a66', 'nonce': 1, 'value': '0x0', 'gasLimit': 12500000, 'gasPrice': '0x1', 'gasFeeCap': '0x0', 'gasTipCap': '0x0', 'data': '0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000000', 'dataAbiValues': {'methodSignature': 'setNumber(uint256)', 'inputValues': ['0']}, 'AccessList': None, 'SkipAccountChecks': False}, 'blockNumberDelay': 30636, 'blockTimestampDelay': 98207}]: index: 0
Parsing fail on [{'call': {'from': '0x0000000000000000000000000000000000010000', 'to': '0xa647ff3c36cfab592509e13860ab8c4f28781a66', 'nonce': 0, 'value': '0x0', 'gasLimit': 12500000, 'gasPrice': '0x1', 'gasFeeCap': '0x0', 'gasTipCap': '0x0', 'data': '0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000000', 'dataAbiValues': {'methodSignature': 'setNumber(uint256)', 'inputValues': ['0']}, 'AccessList': None, 'SkipAccountChecks': False}, 'blockNumberDelay': 4563, 'blockTimestampDelay': 45901}]: index: 1
Parsing fail on [{'call': {'from': '0x0000000000000000000000000000000000030000', 'to': '0xa647ff3c36cfab592509e13860ab8c4f28781a66', 'nonce': 1, 'value': '0x0', 'gasLimit': 12500000, 'gasPrice': '0x1', 'gasFeeCap': '0x0', 'gasTipCap': '0x0', 'data': '0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000000', 'dataAbiValues': {'methodSignature': 'setNumber(uint256)', 'inputValues': ['0']}, 'AccessList': None, 'SkipAccountChecks': False}, 'blockNumberDelay': 40210, 'blockTimestampDelay': 360624}]: index: 2
Parsing fail on [{'call': {'from': '0x0000000000000000000000000000000000020000', 'to': '0xa647ff3c36cfab592509e13860ab8c4f28781a66', 'nonce': 0, 'value': '0x0', 'gasLimit': 12500000, 'gasPrice': '0x1', 'gasFeeCap': '0x0', 'gasTipCap': '0x0', 'data': '0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000000', 'dataAbiValues': {'methodSignature': 'setNumber(uint256)', 'inputValues': ['0']}, 'AccessList': None, 'SkipAccountChecks': False}, 'blockNumberDelay': 23883, 'blockTimestampDelay': 157607}]: index: 3
Parsing fail on [{'call': {'from': '0x0000000000000000000000000000000000020000', 'to': '0xa647ff3c36cfab592509e13860ab8c4f28781a66', 'nonce': 0, 'value': '0x0', 'gasLimit': 12500000, 'gasPrice': '0x1', 'gasFeeCap': '0x0', 'gasTipCap': '0x0', 'data': '0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000000', 'dataAbiValues': {'methodSignature': 'setNumber(uint256)', 'inputValues': ['0']}, 'AccessList': None, 'SkipAccountChecks': False}, 'blockNumberDelay': 1, 'blockTimestampDelay': 56038}]: index: 4
Parsing fail on [{'call': {'from': '0x0000000000000000000000000000000000010000', 'to': '0xa647ff3c36cfab592509e13860ab8c4f28781a66', 'nonce': 0, 'value': '0x0', 'gasLimit': 12500000, 'gasPrice': '0x1', 'gasFeeCap': '0x0', 'gasTipCap': '0x0', 'data': '0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000000', 'dataAbiValues': {'methodSignature': 'setNumber(uint256)', 'inputValues': ['0']}, 'AccessList': None, 'SkipAccountChecks': False}, 'blockNumberDelay': 0, 'blockTimestampDelay': 267796}]: index: 5
Parsing fail on [{'call': {'from': '0x0000000000000000000000000000000000030000', 'to': '0xa647ff3c36cfab592509e13860ab8c4f28781a66', 'nonce': 1, 'value': '0x0', 'gasLimit': 12500000, 'gasPrice': '0x1', 'gasFeeCap': '0x0', 'gasTipCap': '0x0', 'data': '0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000000', 'dataAbiValues': {'methodSignature': 'setNumber(uint256)', 'inputValues': ['0']}, 'AccessList': None, 'SkipAccountChecks': False}, 'blockNumberDelay': 0, 'blockTimestampDelay': 2}]: index: 6
Parsing fail on [{'call': {'from': '0x0000000000000000000000000000000000010000', 'to': '0xa647ff3c36cfab592509e13860ab8c4f28781a66', 'nonce': 0, 'value': '0x0', 'gasLimit': 12500000, 'gasPrice': '0x1', 'gasFeeCap': '0x0', 'gasTipCap': '0x0', 'data': '0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000000', 'dataAbiValues': {'methodSignature': 'setNumber(uint256)', 'inputValues': ['0']}, 'AccessList': None, 'SkipAccountChecks': False}, 'blockNumberDelay': 0, 'blockTimestampDelay': 415822}]: index: 7
Parsing fail on [{'call': {'from': '0x0000000000000000000000000000000000030000', 'to': '0xa647ff3c36cfab592509e13860ab8c4f28781a66', 'nonce': 1, 'value': '0x0', 'gasLimit': 12500000, 'gasPrice': '0x1', 'gasFeeCap': '0x0', 'gasTipCap': '0x0', 'data': '0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000000', 'dataAbiValues': {'methodSignature': 'setNumber(uint256)', 'inputValues': ['0']}, 'AccessList': None, 'SkipAccountChecks': False}, 'blockNumberDelay': 8467, 'blockTimestampDelay': 15389}]: index: 8
Parsing fail on [{'call': {'from': '0x0000000000000000000000000000000000010000', 'to': '0xa647ff3c36cfab592509e13860ab8c4f28781a66', 'nonce': 0, 'value': '0x0', 'gasLimit': 12500000, 'gasPrice': '0x1', 'gasFeeCap': '0x0', 'gasTipCap': '0x0', 'data': '0x3fb5c1cb0000000000000000000000000000000000000000000000000000000000000000', 'dataAbiValues': {'methodSignature': 'setNumber(uint256)', 'inputValues': ['0']}, 'AccessList': None, 'SkipAccountChecks': False}, 'blockNumberDelay': 18801, 'blockTimestampDelay': 413907}]: index: 9
Generated a test file in ./test/FuzzCounter_Medusa_Test.t.sol
Done!

[Bug-Candidate]: Echidna reproducers can have reverting transactions

Describe the issue:

It is possible for echidna reproducers or corpus entries to have transactions that revert. When those transactions are converted to a foundry test, the whole test fails.

Code example to reproduce the issue:

It requires quite a bit of "luck" to generate one of those call sequences, as they are usually optimized during shrinking. But using a low value for the shrinking runs can help finding one, I guess.

Version:

commit 4db6306 + PR #32

Relevant log output:

No response

Improve testing

Describe the desired feature

  • Fix failing Medusa tests by:
    • Adding a medusa corpus for value transfer
    • Removing non-failing call sequences from the corpora
  • Add unit tests for error handling
  • Refactor tests to reduce code duplication
  • Add targeted tests for bytes and string decoding
  • Add testing guidance to CONTRIBUTING.md
  • Refactor tests so test files are generated in a temporary dir and removed upon test completion

Add different modes to harness generation

Describe the desired feature

Separate harness generation into three different modes:

  • Harness functions are directly called without defining Actors or using hevm.prank. --mode simple

  • Harness functions use hevm.prank to switch users. --mode prank

  • Harness functions call Actor functions which are used as proxies for user actions --mode actors

  • Add --mode config flag to the template parser and to the configuration file

  • Refactor harness generation so that it does not need to generate actors

  • Add prank template strings

[Bug-Candidate]: Possible differences in addresses

Describe the issue:

It can happen that in the corpus a function call has the address of the echidna contract as a parameter, for example callSomething(24, 17, 0x00a329c0648769A73afAc7F9381E08FB43dBEA72).

In that case, it is possible that the address of the contract deployed in the tests will be different, leading to non-reproducible behavior due to that difference. In that case, the call should be replaced with callSomething(24, 17, address(ContractDeployedInTest))

Code example to reproduce the issue:

Private code.

Version:

N/A

Relevant log output:

No response

Cleanup the corpus

Describe the desired feature

Sometimes, Echidna segfaults because, I would guess, some of the call sequences trigger an invalidate state on the tool.

It would be nice to somehow remove only the invalid tx and keep the previous ones that are not "corrupted"

This seems like a quick fix to the segfault problem, and could perhaps be fixed in https://github.com/crytic/echidna directly, so please lmk if I should open an issue there instead.

[Bug-Candidate]: If `deployContracts` is used, the generated test probably won't work

Describe the issue:

Echidna allows contracts to be deployed to specific addresses using the deployContracts configuration option. However, when the tests are generated, only the harness is constructed and the other contracts are not deployed.

Not sure if this is an easy fix, just leaving it here for reference.

Code example to reproduce the issue:

Not an exact reproducer, but a general idea.

In echidna config file:

deployContracts:  [["0x12345", "ExampleContract"]]

In the echidna test contract:

constructor() {
    ExampleContract ec = ExampleContract(0x12345);
    uint256 value1 = ec.doSomething();
    assert(value1 == 123);
}

Version:

0.2.0

Relevant log output:

No response

Real time coverage report chart

Describe the desired feature

I would like to get a coverage report chart by parsing Echidna/Medusa logs

Example

echidna . --target CryticTester --config echidna.yaml | fuzz-utils --chart

image
(Source)

or

medusa fuzz | fuzz-utils --chart

Also:

[I] ➜ cat /tmp/echidna.log
[2024-04-04 14:27:49.59] Compiling CryticTester.sol... Done! (0.799778s)
Analyzing contract: CryticTester.sol:CryticTester
[2024-04-04 14:27:53.46] Running slither on CryticTester.sol... Done! (0.939738s)
Loaded 0 transaction sequences from echidna/reproducers
Loaded 0 transaction sequences from echidna/coverage
[2024-04-04 14:27:54.41] [Worker 6] New maximum value of echidna_optimize_extracted_profit: 0
[2024-04-04 14:27:54.41] [Worker 2] New maximum value of echidna_optimize_extracted_profit: 0
[2024-04-04 14:27:54.41] [Worker 3] New maximum value of echidna_optimize_extracted_profit: 0
[2024-04-04 14:27:54.41] [Worker 7] New maximum value of echidna_optimize_extracted_profit: 0
[2024-04-04 14:27:54.41] [Worker 0] New maximum value of echidna_optimize_extracted_profit: 0
[2024-04-04 14:27:54.41] [Worker 4] New maximum value of echidna_optimize_extracted_profit: 0
[2024-04-04 14:27:54.41] [Worker 5] New maximum value of echidna_optimize_extracted_profit: 0
[2024-04-04 14:27:57.41] [status] tests: 0/1, fuzzing: 0/1000000, values: [0], cov: 2136, corpus: 0
[2024-04-04 14:28:00.41] [status] tests: 0/1, fuzzing: 0/1000000, values: [0], cov: 3053, corpus: 0
[2024-04-04 14:28:03.41] [status] tests: 0/1, fuzzing: 0/1000000, values: [0], cov: 3874, corpus: 0
[2024-04-04 14:28:06.41] [status] tests: 0/1, fuzzing: 0/1000000, values: [0], cov: 4086, corpus: 0
[2024-04-04 14:28:09.41] [status] tests: 0/1, fuzzing: 0/1000000, values: [0], cov: 4122, corpus: 0
[2024-04-04 14:28:12.47] [status] tests: 0/1, fuzzing: 0/1000000, values: [0], cov: 4682, corpus: 0
[2024-04-04 14:28:15.47] [status] tests: 0/1, fuzzing: 0/1000000, values: [0], cov: 5026, corpus: 0
[2024-04-04 14:28:18.86] [status] tests: 0/1, fuzzing: 0/1000000, values: [0], cov: 5542, corpus: 0
[2024-04-04 14:28:20.31] [Worker 7] New coverage: 5542 instr, 5 contracts, 1 seqs in corpus
[2024-04-04 14:28:20.63] [Worker 5] New coverage: 5542 instr, 5 contracts, 2 seqs in corpus
[2024-04-04 14:28:21.05] [Worker 2] New coverage: 5542 instr, 5 contracts, 3 seqs in corpus
[2024-04-04 14:28:21.86] [status] tests: 0/1, fuzzing: 303/1000000, values: [0], cov: 5542, corpus: 3

[I] ➜ tail -f /tmp/echidna.log | fuzz-utils --chart

[Bug-Candidate]: Functions with the same signature can be generated multiple times

Describe the issue:

When multiple contracts have functions with the same signature fuzz-utils will generate the same function multiple times, preventing compilation.

We should:

  • Add a prefix to the function e.g., contractName_functionName when generating
  • Detect if a function is overriden and only generate one instance in that case

Code example to reproduce the issue:

contract A {
  function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
    // Do something
  }
}

contract B is A {
  function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
    // Do something else
  }
}

Version:

0.2.0

Relevant log output:

N/A

Make CLI arguments optional

Describe the desired feature

Can any of the CLI arguments be optional by using defaults?
I'd be happy just specifying fuzz-utils contracts/Contract.sol and it running with it

  • Can -cd default to .corpus or some other?
  • Can -c be inferred if there is one main contract defined in the specified target?
  • Can -td be test?
  • Can -f default to either echidna/medusa? Preferably medusa
  • Can -i be inferred, since the target and test directory are given

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.