Skip to content

Commit 4fb6833

Browse files
Amxxfrangio
andauthored
Formal verification using Certora (#4084)
Co-authored-by: Francisco Giordano <fg@frang.io>
1 parent de520fe commit 4fb6833

34 files changed

+1011
-1319
lines changed
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
name: formal verification
2+
3+
on:
4+
push:
5+
branches:
6+
- master
7+
- release-v*
8+
pull_request: {}
9+
workflow_dispatch: {}
10+
11+
env:
12+
PIP_VERSION: '3.10'
13+
JAVA_VERSION: '11'
14+
SOLC_VERSION: '0.8.19'
15+
16+
jobs:
17+
apply-diff:
18+
runs-on: ubuntu-latest
19+
steps:
20+
- uses: actions/checkout@v3
21+
- name: Apply patches
22+
run: make -C certora apply
23+
24+
verify:
25+
runs-on: ubuntu-latest
26+
if: github.event_name != 'pull_request' || contains(github.event.pull_request.labels.*.name, 'formal-verification')
27+
steps:
28+
- uses: actions/checkout@v3
29+
- name: Set up environment
30+
uses: ./.github/actions/setup
31+
- name: Install python
32+
uses: actions/setup-python@v4
33+
with:
34+
python-version: ${{ env.PIP_VERSION }}
35+
cache: 'pip'
36+
- name: Install python packages
37+
run: pip install -r requirements.txt
38+
- name: Install java
39+
uses: actions/setup-java@v3
40+
with:
41+
distribution: temurin
42+
java-version: ${{ env.JAVA_VERSION }}
43+
- name: Install solc
44+
run: |
45+
wget https://github.com/ethereum/solidity/releases/download/v${{ env.SOLC_VERSION }}/solc-static-linux
46+
sudo mv solc-static-linux /usr/local/bin/solc
47+
chmod +x /usr/local/bin/solc
48+
- name: Verify specification
49+
run: |
50+
make -C certora apply
51+
node certora/run.js >> "$GITHUB_STEP_SUMMARY"
52+
env:
53+
CERTORAKEY: ${{ secrets.CERTORAKEY }}

certora/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
patched

certora/Makefile

Lines changed: 44 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,54 @@
11
default: help
22

3-
PATCH = applyHarness.patch
4-
CONTRACTS_DIR = ../contracts
5-
MUNGED_DIR = munged
3+
SRC := ../contracts
4+
DST := patched
5+
DIFF := diff
6+
SRCS := $(shell find $(SRC) -type f)
7+
DSTS := $(shell find $(DST) -type f)
8+
DIFFS := $(shell find $(DIFF) -type f)
69

10+
###############################################################################
11+
# Apply all patches in the $DIFF folder to the $DST folder
12+
apply: $(DST) $(patsubst $(DIFF)/%.patch,$(DST)/%,$(subst _,/,$(DIFFS)))
13+
14+
# Reset the $DST folder
15+
$(DST): FORCE
16+
@rm -rf $@
17+
@cp -r $(SRC) $@
18+
19+
# Update a solidity file in the $DST directory using the corresponding patch
20+
$(DST)/%.sol: FORCE
21+
@echo Applying patch to $@
22+
@patch -p0 -d $(DST) < $(patsubst $(DST)_%,$(DIFF)/%.patch,$(subst /,_,$@))
23+
24+
###############################################################################
25+
# Record all difference between $SRC and $DST in patches
26+
record: $(DIFF) $(patsubst %,$(DIFF)/%.patch,$(subst /,_,$(subst $(SRC)/,,$(SRCS)) $(subst $(DST)/,,$(DSTS))))
27+
28+
# Create the $DIFF folder
29+
$(DIFF): FORCE
30+
@rm -rf $@
31+
@mkdir $@
32+
33+
# Create the patch file by comparing the source and the destination
34+
$(DIFF)/%.patch: FORCE
35+
@echo Generating patch $@
36+
@diff -ruN \
37+
$(patsubst $(DIFF)/%.patch,$(SRC)/%,$(subst _,/,$@)) \
38+
$(patsubst $(DIFF)/%.patch,$(DST)/%,$(subst _,/,$@)) \
39+
| sed 's+$(SRC)/++g' \
40+
| sed 's+$(DST)/++g' \
41+
> $@
42+
@[ -s $@ ] || rm $@
43+
44+
###############################################################################
745
help:
846
@echo "usage:"
47+
@echo " make apply: create $(DST) directory by applying the patches to $(SRC)"
48+
@echo " make record: record the patches capturing the differences between $(SRC) and $(DST)"
949
@echo " make clean: remove all generated files (those ignored by git)"
10-
@echo " make $(MUNGED_DIR): create $(MUNGED_DIR) directory by applying the patch file to $(CONTRACTS_DIR)"
11-
@echo " make record: record a new patch file capturing the differences between $(CONTRACTS_DIR) and $(MUNGED_DIR)"
12-
13-
munged: $(wildcard $(CONTRACTS_DIR)/*.sol) $(PATCH)
14-
rm -rf $@
15-
cp -r $(CONTRACTS_DIR) $@
16-
patch -p0 -d $@ < $(PATCH)
17-
18-
record:
19-
diff -ruN $(CONTRACTS_DIR) $(MUNGED_DIR) | sed 's+../contracts/++g' | sed 's+munged/++g' > $(PATCH)
2050

2151
clean:
2252
git clean -fdX
23-
touch $(PATCH)
2453

54+
FORCE: ;

certora/applyHarness.patch

Lines changed: 0 additions & 101 deletions
This file was deleted.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
import "../patched/access/AccessControl.sol";
6+
7+
contract AccessControlHarness is AccessControl {}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
import "../patched/token/ERC20/ERC20.sol";
6+
import "../patched/token/ERC20/extensions/ERC20Permit.sol";
7+
import "../patched/token/ERC20/extensions/ERC20FlashMint.sol";
8+
9+
contract ERC20FlashMintHarness is ERC20, ERC20Permit, ERC20FlashMint {
10+
uint256 someFee;
11+
address someFeeReceiver;
12+
13+
constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) {}
14+
15+
function mint(address account, uint256 amount) external {
16+
_mint(account, amount);
17+
}
18+
19+
function burn(address account, uint256 amount) external {
20+
_burn(account, amount);
21+
}
22+
23+
// public accessor
24+
function flashFeeReceiver() public view returns (address) {
25+
return someFeeReceiver;
26+
}
27+
28+
// internal hook
29+
function _flashFee(address, uint256) internal view override returns (uint256) {
30+
return someFee;
31+
}
32+
33+
function _flashFeeReceiver() internal view override returns (address) {
34+
return someFeeReceiver;
35+
}
36+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
pragma solidity ^0.8.0;
4+
5+
import "../patched/token/ERC20/ERC20.sol";
6+
import "../patched/token/ERC20/extensions/ERC20Permit.sol";
7+
8+
contract ERC20PermitHarness is ERC20, ERC20Permit {
9+
constructor(string memory name, string memory symbol) ERC20(name, symbol) ERC20Permit(name) {}
10+
11+
function mint(address account, uint256 amount) external {
12+
_mint(account, amount);
13+
}
14+
15+
function burn(address account, uint256 amount) external {
16+
_burn(account, amount);
17+
}
18+
}

certora/harnesses/ERC20VotesHarness.sol

Lines changed: 0 additions & 28 deletions
This file was deleted.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// SPDX-License-Identifier: MIT
2+
3+
import "../patched/interfaces/IERC3156FlashBorrower.sol";
4+
5+
pragma solidity ^0.8.0;
6+
7+
contract ERC3156FlashBorrowerHarness is IERC3156FlashBorrower {
8+
bytes32 somethingToReturn;
9+
10+
function onFlashLoan(address, address, uint256, uint256, bytes calldata) external view override returns (bytes32) {
11+
return somethingToReturn;
12+
}
13+
}

0 commit comments

Comments
 (0)