The purpose of this tool is to transform the foundry broadcast JSON file to an Etheno-like JSON file for seamless Foundry integration with Echidna.
Make sure you have Rust installed.
Install from crates.io:
cargo install foundry2echidna
Install from source:
git clone https://github.com/ChmielewskiKamil/foundry2echidna/foundry2echidna &&
cd foundry2echidna &&
cargo install --path .
Once you have foundry2echidna
installed, you are ready to transform broadcast files.
- In the root of your Foundry project, run the command
foundry2echidna
. By default, if no arguments were passed, the tool will look for the following:
- Your broadcast in
broadcast/*.s.sol/31337/run-latest.json
- And will output to
src/crytic/init.json
You can pass custom input and output paths like this:
foundry2echidna --input-path path/to/broadcast.json --output-path path/to/init.json
Or, for short:
foundry2echidna -i path/to/broadcast.json -o path/to/init.json
- Seed Echidna with the generated
init.json
file. Add the following to yourechidna_config.yaml
:
initialize: path/to/init.json
(for your custom output path)- or
initialize: src/crytic/init.json
(for the default output path, if no arguments were provided)
- Update your
EchidnaTest
contract, just like you would be interacting with the contracts deployed on the blockchain.
- Get the appropriate contract addresses from the broadcast file generated by Foundry (
run-latest.json
).
// Get address of the Counter contract from the broadcast file
counter = Counter(0x1234...);
// This works for contracts deployed by Factories and function calls as well
counterFactory = CounterFactory(0x456...);
anotherCounterDeployedByFactory = AnotherCounter(0x678...);
- Run Echidna.
Here you can find dev documentation on docs.rs.
You can use the transform_broadcast
function that takes two arguments:
- input_path
- output_path
to deserialize and serialize broadcast files.
Etheno handles two main groups of events* (via EventSummaryPlugin
):
- Contract creations
- Function calls
ContractCreated
event has the following fields:
event
- this is just the name of the type of the event ->ContractCreated
from
- this is the address of the contract creatorcontract_address
- deployed contract addressgas_used
- the amount of gas used in the transactiongas_price
- gas price used in the transactiondata
- transaction datavalue
- Ether sent in the transaction
FunctionCall
event has the following fields:
event
- this is just the name of the type of the event ->FunctionCall
from
- address of an account that made the callto
- address of an account that has been calledgas_used
- the amount of gas used in the transactiongas_price
- gas price used in the transactiondata
- transaction datavalue
- Ether sent in the transaction
*There is also block mined event, but it's not crucial for Echidna setup (?)
Foundry broadcast structure is more complicated than that, but we only care about a couple of fields. Since we want to transform the broadcast into this Etheno-like structure, the appropriate fields must be mapped together.
Etheno field | Foundry field |
---|---|
event |
transactions[i].transaction_type |
from |
transactions[i].transaction.from |
to |
transactions[i].transaction.to |
contract_address |
transactions[i].contract_address |
gas_used |
receipts[i].gas_used |
gas_price |
receipts[i].effective_gas_price |
data |
transactions[i].transaction.data |
value |
transactions[i].transaction.value |