This repository contains a project that will be used during a Secureum workshop on Kontrol. Contracts present in this repository are modified for educational purposes, please DO NOT use them in production.
Documentation and installation instructions for Kontrol can be found in Kontrol Book. Source code for Kontol is available in Kontrol repository.
The first workshop for Kontrol is focused on basic usage of its commands in application to WETH9 contract and the tests we have defined for it.
To clone and build this project, run
git clone https://github.com/runtimeverification/secureum-kontrol.git && cd secureum-kontrol
followed by
kontrol build
This command will run forge build
under the hood, and will, then, use the produced compilation artifacts to generate K definitions that can be verified. You can inspect the out/
folder to view the artifacts produced by kontrol build
and make sure that it executed successfully.
To prove that WETH9 approve()
function changes allowance
correctly, you can run the following command:
kontrol prove --match-test 'WETH9Test.test_approve(address,address,uint256)'
The process should end successfully, indicating that this property is always true and, whatever the values of from
, to
, and amount
are, approve()
behaves correctly.
The test being executed is as follows:
function test_approve(address from, address to, uint256 amount) public {
vm.prank(from);
asset.approve(to, amount);
uint256 toAllowance = asset.allowance(from, to);
assert(toAllowance == amount);
}
The second workshop for Kontrol will cover several aspects, including ERC4626 tests, addressing verification challenges such as loops and dynamically-sized Solidity types, and proving equivalence between Solidity and low-level gas optimized implementations for Solady.
In the first part of the workshop, the following commands would help build the project and run two tests for the ERC4626 implementation we are using:
kontrol build
kontrol prove --match-test test_totalAssets_doesNotRevert --match-test test_totalAssets_revertsWhenPaused -j2
The first test, checking if test_totalAssets_doesNotRevert
never reverts, as requested by the EIP
function test_totalAssets_doesNotRevert(address caller) public {
_notBuiltinAddress(caller);
vm.prank(caller); vault.totalAssets();
}
will revert, since the implementation of the ERC4626 vault we are using here (for illustration purposes!) reverts if the contract has been paused.
Kontrol, and FV in general, can be used to assert equivalence between different implementations of smart contract functions. To prove that a highly optimized implementation of mulWad
funciton in Solady is equivalent to a more readable Solidity version, run
kontrol build --require lemmas/eq-lemmas.k --module-import EquivalenceTest:EQ-LEMMAS
to build a project with lemmas that, as discussed in the workshop, are needed for the following test to succeed:
function test_mulWad(uint256 x, uint256 y) public {
if (y == 0 || x <= type(uint256).max / y) {
uint256 zSpec = (x * y) / WAD;
uint256 zImpl = mulWad(x, y);
assert(zImpl == zSpec);
} else {
vm.expectRevert();
this.mulWad(x, y);
}
}
Then, run
kontrol prove --match-test testMulWad --smt-solver 10000
If you need any assistance, please reach out to us in a dedicated Secureum Discord channel or RV Discord.