Skip to content

Commit f1ff61b

Browse files
Merge pull request #36 from crytic/dev-medusa
Initial medusa support for the CI
2 parents 61133a7 + 4f3ca42 commit f1ff61b

File tree

10 files changed

+615
-13
lines changed

10 files changed

+615
-13
lines changed

.github/workflows/examples.yaml .github/workflows/echidna.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: Test examples
1+
name: Test examples using Echidna
22

33
on:
44
push:

.github/workflows/medusa.yaml

+117
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
name: Test examples using Medusa
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
pull_request:
8+
branches:
9+
- "*"
10+
11+
env:
12+
FOUNDRY_PROFILE: ci
13+
14+
jobs:
15+
foundry:
16+
name: Test Foundry examples
17+
runs-on: ubuntu-latest
18+
steps:
19+
- name: Checkout repository
20+
uses: actions/checkout@v3
21+
with:
22+
submodules: recursive
23+
24+
- name: Install Foundry
25+
uses: foundry-rs/foundry-toolchain@v1
26+
27+
- name: Go setup
28+
uses: actions/setup-go@v4
29+
with:
30+
go-version: "^1.18.1"
31+
32+
- name: Install medusa
33+
run: |
34+
git clone https://github.com/crytic/medusa.git
35+
cd medusa
36+
go build -o medusa -v .
37+
go install -v .
38+
sudo cp medusa /usr/bin
39+
pip install crytic-compile
40+
41+
- name: Compile ERC20 Foundry example
42+
working-directory: tests/ERC20/foundry
43+
run: forge build --build-info
44+
45+
- name: Run Medusa for Internal ERC20 tests
46+
working-directory: tests/ERC20/foundry
47+
run: |
48+
medusa fuzz --target-contracts CryticERC20InternalHarness --config medusa-config.json
49+
50+
- name: Run Medusa for External ERC20 tests
51+
working-directory: tests/ERC20/foundry
52+
run: |
53+
medusa fuzz --target-contracts CryticERC20ExternalHarness --config medusa-config-ext.json
54+
55+
- name: Compile ERC4646 Foundry example
56+
working-directory: tests/ERC4626/foundry
57+
run: forge build --build-info
58+
59+
- name: Run Medusa for External ERC4626 tests
60+
working-directory: tests/ERC4626/foundry
61+
run: |
62+
medusa fuzz --target-contracts CryticERC4626InternalHarness --config medusa-config.json
63+
64+
hardhat:
65+
name: Test Hardhat examples
66+
runs-on: ubuntu-latest
67+
steps:
68+
- name: Checkout repository
69+
uses: actions/checkout@v3
70+
with:
71+
submodules: recursive
72+
73+
- name: Set up Nodejs
74+
uses: actions/setup-node@v3
75+
with:
76+
node-version: 16
77+
78+
- name: Install dependencies and compile ERC20 example
79+
working-directory: tests/ERC20/hardhat
80+
run: |
81+
npm ci
82+
npx hardhat compile --force
83+
84+
- name: Install dependencies and compile ERC4626 example
85+
working-directory: tests/ERC4626/hardhat
86+
run: |
87+
npm ci
88+
npx hardhat compile --force
89+
90+
- name: Go setup
91+
uses: actions/setup-go@v4
92+
with:
93+
go-version: "^1.18.1"
94+
95+
- name: Install medusa
96+
run: |
97+
git clone https://github.com/crytic/medusa.git
98+
cd medusa
99+
go build -o medusa -v .
100+
go install -v .
101+
sudo cp medusa /usr/bin
102+
pip install crytic-compile
103+
104+
- name: Run Medusa for Internal ERC20 tests
105+
working-directory: tests/ERC20/hardhat
106+
run: |
107+
medusa fuzz --target-contracts CryticERC20InternalHarness --config medusa-config.json
108+
109+
- name: Run Medusa for External ERC20 tests
110+
working-directory: tests/ERC20/hardhat
111+
run: |
112+
medusa fuzz --target-contracts CryticERC20ExternalHarness --config medusa-config-ext.json
113+
114+
- name: Run Medusa for External ERC4626 tests
115+
working-directory: tests/ERC4626/hardhat
116+
run: |
117+
medusa fuzz --target-contracts CryticERC4626Harness --config medusa-config.json

CONTRIBUTING.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Bug reports and feature suggestions can be submitted to our issue tracker. For b
1010

1111
## Questions
1212

13-
Questions can be submitted to the issue tracker, but you may get a faster response if you ask in our [chat room](https://slack.empirehacking.nyc/) (in the #ethereum channel).
13+
Questions can be submitted to the issue tracker, but you may get a faster response if you ask in our [chat room](https://slack.empirehacking.nyc) (in the #ethereum channel).
1414

1515
## Code
1616

README.md

+54-11
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ The goals of these properties are to:
3333
- Ensure adherence to relevant standards
3434
- Provide educational guidance for writing invariants
3535

36-
The properties can be used through unit tests or through fuzzing with [Echidna](https://github.com/crytic/echidna).
36+
The properties can be used through unit tests or through fuzzing with [Echidna](https://github.com/crytic/echidna) or [Medusa](https://github.com/crytic/medusa).
3737

3838
## Testing the properties with fuzzing
3939

40-
1. Install [Echidna](https://github.com/crytic/echidna#installation).
40+
1. Install [Echidna](https://github.com/crytic/echidna#installation) or [Medusa](https://github.com/crytic/medusa/blob/master/docs/src/getting_started/installation.md#installation).
4141
2. Import the properties into to your project:
4242

4343
- In case of using Hardhat, use: `npm install https://github.com/crytic/properties.git` or `yarn add https://github.com/crytic/properties.git`
@@ -118,6 +118,8 @@ contract CryticTokenMock is MyToken, PropertiesConstants {
118118

119119
#### Configuration
120120

121+
**Echidna**
122+
121123
Create the following Echidna config file
122124

123125
```yaml
@@ -126,26 +128,67 @@ testMode: assertion
126128
testLimit: 100000
127129
deployer: "0x10000"
128130
sender: ["0x10000", "0x20000", "0x30000"]
131+
# Uncomment the following line for external testing
132+
#allContracts: true
129133
```
130134

131-
If you're using external testing, you will also need to specify:
132-
133-
```yaml
134-
allContracts: true
135+
**Medusa**
136+
137+
Create the following Medusa config file:
138+
139+
```json
140+
{
141+
"fuzzing": {
142+
"testLimit": 100000,
143+
"corpusDirectory": "tests/medusa-corpus",
144+
"deployerAddress": "0x10000",
145+
"senderAddresses": [
146+
"0x10000",
147+
"0x20000",
148+
"0x30000"
149+
],
150+
"assertionTesting": {
151+
"enabled": true
152+
},
153+
"propertyTesting": {
154+
"enabled": false
155+
},
156+
"optimizationTesting": {
157+
"enabled": false,
158+
},
159+
},
160+
// Uncomment the following lines for external testing
161+
// "testing": {
162+
// "testAllContracts": true
163+
// },
164+
"compilation": {
165+
"platform": "crytic-compile",
166+
"platformConfig": {
167+
"target": ".",
168+
"solcVersion": "",
169+
"exportDirectory": "",
170+
"args": ["--foundry-compile-all"]
171+
}
172+
}
173+
}
135174
```
136175

137-
To perform more than one test, save the files with a descriptive path, to identify what test each file or corpus belongs to. For these examples, we use `tests/crytic/erc20/echidna-internal.yaml` and `tests/crytic/erc20/echidna-external.yaml` for the Echidna tests for ERC20. We recommended to modify the `corpusDir` for external tests accordingly.
176+
To perform more than one test, save the files with a descriptive path, to identify what test each file or corpus belongs to. For instace, for these examples, we use `tests/crytic/erc20/echidna-internal.yaml` and `tests/crytic/erc20/echidna-external.yaml` for the Echidna tests for ERC20. We recommended to modify the corpus directory config opction for external tests accordingly.
138177

139-
The above configuration will start Echidna in assertion mode. Contract will be deployed from address `0x10000`, and transactions will be sent from the owner and two different users (`0x20000` and `0x30000`). There is an initial limit of `100000` tests, but depending on the token code complexity, this can be increased. Finally, once Echidna finishes the fuzzing campaign, corpus and coverage results will be available in the `tests/crytic/erc20/echidna-corpus-internal` directory.
178+
The above configuration will start Echidna or Medusa in assertion mode. The target contract(s) will be deployed from address `0x10000`, and transactions will be sent from the owner as well as two different users (`0x20000` and `0x30000`). There is an initial limit of `100000` tests, but depending on the token code complexity, this can be increased. Finally, once our fuzzing tools finish the fuzzing campaign, corpus and coverage results will be available in the specified corpus directory.
140179

141180
#### Run
142181

143-
Run Echidna:
182+
**Echidna**
144183

145184
- For internal testing: `echidna . --contract CryticERC20InternalHarness --config tests/crytic/erc20/echidna-internal.yaml`
146185
- For external testing: `echidna . --contract CryticERC20ExternalHarness --config tests/crytic/erc20/echidna-external.yaml`
147186

148-
Finally, inspect the coverage report in `tests/crytic/erc20/echidna-corpus-internal` or `tests/crytic/erc20/echidna-corpus-external` when it finishes.
187+
**Medusa**
188+
189+
- Go to the directory `cd tests/crytic/erc20`
190+
- For internal testing: `medusa fuzz --target-contracts CryticERC20InternalHarness --config medusa-internal.yaml`
191+
- For external testing: `medusa fuzz --target-contracts CryticERC20ExternalHarness --config medusa-external.yaml`
149192

150193
#### Example: Output for a compliant token
151194

@@ -417,7 +460,7 @@ Run the test suite using `echidna . --contract CryticABDKMath64x64Harness --seq-
417460
## Additional resources
418461

419462
- [Building secure contracts](https://secure-contracts.com/program-analysis/index.html)
420-
- Our [EmpireSlacking](https://slack.empirehacking.nyc/) slack server, channel #ethereum
463+
- Our [EmpireSlacking](https://slack.empirehacking.nyc) slack server, channel #ethereum
421464
- Watch our [fuzzing workshop](https://www.youtube.com/watch?v=QofNQxW_K08&list=PLciHOL_J7Iwqdja9UH4ZzE8dP1IxtsBXI)
422465

423466
# Helper functions
+80
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
{
2+
"fuzzing": {
3+
"workers": 10,
4+
"workerResetLimit": 50,
5+
"timeout": 0,
6+
"testLimit": 500000,
7+
"callSequenceLength": 100,
8+
"corpusDirectory": "tests/medusa-corpus-ext",
9+
"coverageEnabled": true,
10+
"targetContracts": [],
11+
"targetContractsBalances": [],
12+
"constructorArgs": {},
13+
"deployerAddress": "0x10000",
14+
"senderAddresses": [
15+
"0x10000",
16+
"0x20000",
17+
"0x30000"
18+
],
19+
"blockNumberDelayMax": 60480,
20+
"blockTimestampDelayMax": 604800,
21+
"blockGasLimit": 125000000,
22+
"transactionGasLimit": 12500000,
23+
"testing": {
24+
"stopOnFailedTest": true,
25+
"stopOnFailedContractMatching": false,
26+
"stopOnNoTests": true,
27+
"testAllContracts": true,
28+
"traceAll": false,
29+
"assertionTesting": {
30+
"enabled": true,
31+
"testViewMethods": false,
32+
"panicCodeConfig": {
33+
"failOnCompilerInsertedPanic": false,
34+
"failOnAssertion": true,
35+
"failOnArithmeticUnderflow": false,
36+
"failOnDivideByZero": false,
37+
"failOnEnumTypeConversionOutOfBounds": false,
38+
"failOnIncorrectStorageAccess": false,
39+
"failOnPopEmptyArray": false,
40+
"failOnOutOfBoundsArrayAccess": false,
41+
"failOnAllocateTooMuchMemory": false,
42+
"failOnCallUninitializedVariable": false
43+
}
44+
},
45+
"propertyTesting": {
46+
"enabled": false,
47+
"testPrefixes": [
48+
"property_"
49+
]
50+
},
51+
"optimizationTesting": {
52+
"enabled": false,
53+
"testPrefixes": [
54+
"optimize_"
55+
]
56+
}
57+
},
58+
"chainConfig": {
59+
"codeSizeCheckDisabled": true,
60+
"cheatCodes": {
61+
"cheatCodesEnabled": true,
62+
"enableFFI": false
63+
}
64+
}
65+
},
66+
"compilation": {
67+
"platform": "crytic-compile",
68+
"platformConfig": {
69+
"target": ".",
70+
"solcVersion": "",
71+
"exportDirectory": "",
72+
"args": ["--foundry-compile-all"]
73+
}
74+
},
75+
"logging": {
76+
"level": "info",
77+
"logDirectory": "",
78+
"noColor": false
79+
}
80+
}

0 commit comments

Comments
 (0)