Skip to content

Commit ee04b27

Browse files
authored
Merge pull request #263 from crytic/dev-library-support-echidna
Working with libraries in Echidna
2 parents 24e6d68 + 6c2b4d7 commit ee04b27

File tree

3 files changed

+80
-0
lines changed

3 files changed

+80
-0
lines changed

SUMMARY.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
- [How to test bytecode-only contracts](./program-analysis/echidna/advanced/testing-bytecode.md)
8181
- [How to use hevm cheats to test permit](./program-analysis/echidna/advanced/hevm-cheats-to-test-permit.md)
8282
- [How to seed Echidna with unit tests](./program-analysis/echidna/advanced/end-to-end-testing.md)
83+
- [How to fuzz contracts with external libraries](./program-analysis/echidna/advanced/working-with-libraries.md)
8384
- [Understanding and using `multi-abi`](./program-analysis/echidna/advanced/using-multi-abi.md)
8485
- [Fuzzing tips](./program-analysis/echidna/fuzzing_tips.md)
8586
- [Frequently Asked Questions](./program-analysis/echidna/frequently_asked_questions.md)

program-analysis/echidna/advanced/README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,5 @@
88
- [How to test bytecode-only contracts](./testing-bytecode.md): How to fuzz a contract without bytecode or to perform differential fuzzing between Solidity and Vyper
99
- [How to use hevm cheats to test permit](./hevm-cheats-to-test-permit.md): How to test code that depends on ecrecover signatures using hevm cheat codes
1010
- [How to seed Echidna with unit tests](./end-to-end-testing.md): How to use existing unit tests to seed Echidna
11+
- [How to fuzz contracts with external libraries](./working-with-libraries.md): How to fuzz a contract that has external libraries
1112
- [Understanding and using `multi-abi`](./using-multi-abi.md): What is `multi-abi` testing, and how can it be used
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Working with external libraries
2+
3+
**Table of contents:**
4+
5+
- [Introduction](#introduction)
6+
- [Example code](#example-code)
7+
- [Deploying libraries](#deploying-libraries)
8+
- [Linking libraries](#linking-libraries)
9+
- [Summary](#summary)
10+
11+
## Introduction
12+
13+
Solidity support two types of libraries ([see the documentation](https://docs.soliditylang.org/en/v0.8.19/contracts.html#libraries)):
14+
15+
- If all the functions are internal, the library is compiled into bytecode and added into the contracts that use it.
16+
- If there are some external functions, the library should be deployed into some address. Finally, the bytecode calling the library should be linked.
17+
18+
The following is only needed if your codebase uses libraries that need to be linked.
19+
20+
## Example code
21+
22+
For this tutorial, we will use [the metacoin example](https://github.com/truffle-box/metacoin-box). Let's start compiling it:
23+
24+
```
25+
$ git clone https://github.com/truffle-box/metacoin-box
26+
$ cd metacoin-box
27+
$ npm i
28+
```
29+
30+
## Deploying libraries
31+
32+
Libraries are contracts that need to be deployed first. Fortunately, Echidna allows us to do that easily, using the `deployContracts` option. In the metacoin example, we can use:
33+
34+
```yaml
35+
deployContracts: [["0x1f", "ConvertLib"]]
36+
```
37+
38+
The address where the library should be deployed is arbitrary, but it should be the same as the one in the used during the linking process.
39+
40+
## Linking libraries
41+
42+
Before a contract can use a deployed library, its bytecode requires to be linked (e.g set the address that points to the deployed library contract). Normally, a compilation framework (e.g. truffle) will take care of this. However, in our case, we will use `crytic-compile`, since it is easier to handle all cases from different frameworks just adding one new argument to pass to `crytic-compile` from Echidna:
43+
44+
```yaml
45+
cryticArgs: ["--compile-libraries=(ConvertLib,0x1f)"]
46+
```
47+
48+
Going back to the example, if we have both config options in a single config file (`echidna.yaml`), we can run the metacoin contract
49+
in `exploration` mode:
50+
51+
```
52+
$ echidna . --test-mode exploration --corpus-dir corpus --contract MetaCoin --config echidna.yaml
53+
```
54+
55+
We can use the coverage report to verify that function using the library (`getBalanceInEth`) is not reverting:
56+
57+
```
58+
28 | * | function getBalanceInEth(address addr) public view returns(uint){
59+
29 | * | return ConvertLib.convert(getBalance(addr),2);
60+
30 | | }
61+
```
62+
63+
However, the code of the library itself will not have their coverage displayed correctly:
64+
65+
```
66+
6 | | library ConvertLib{
67+
7 | | function convert(uint amount, uint conversionRate) public pure returns (uint convertedAmount)
68+
8 | | {
69+
9 | | return amount * conversionRate;
70+
10 | | }
71+
11 | | }
72+
```
73+
74+
This is caused by the usage of `delegatecall` to execute contract code and [unfortunately we do not have a workaround for it right now](https://github.com/crytic/echidna/issues/1042).
75+
76+
## Summary
77+
78+
Working with libraries in Echidna is supported. It involves to deploy the library to a particular address using `deployContracts` and then asking `crytic-compile` to link the bytecode with the same address using `--compile-libraries` command line.

0 commit comments

Comments
 (0)