-
Notifications
You must be signed in to change notification settings - Fork 85
Allow targetContract(address(this));
to perform Invariant Testing on Scaffolded Contracts
#506
New issue
Have a question about this project? Sign up for a free Git 8000 Hub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Testing with: // SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "forge-std/Test.sol";
contract InvariantTest is Test {
bool fooCalled;
function setUp() public {
targetContract(address(this));
}
function foo() public {
fooCalled = true;
}
function invariant_this() public {
assertFalse(fooCalled);
}
} On foundry 1.0.0-rc:
But on foundry 1.1.0-stable:
With current halmos, we mirrored the behavior of foundry 1.0.0-rc:
|
FYI the behavior is a little weird, and may cause some issues. Take this test for example: // SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;
import "forge-std/Test.sol";
contract InvariantTest is Test {
bool fooCalled;
uint256 invariantCalledNum;
uint256 setUpCalledNum;
function setUp() public {
targetContract(address(this));
}
function foo() public {
fooCalled = true;
}
function invariant_foo_called() public view {
assert(!fooCalled);
}
function invariant_considered_target() public {
// this is evaluated for invariant violations, but also considered a target state-changing function
invariantCalledNum++;
assertLt(invariantCalledNum, 10);
}
function invariant_setUp_considered_target() public {
setUpCalledNum++;
assertLt(setUpCalledNum, 10);
}
}
This shows that the target functions are not just I think the special functions like |
Thank you for digging deeper @0xkarmacoma From my POV we'd want to exclude exclusively the Every other function can have storage changes, that can influence other functions, meaning they should probably be included If we'd wanted an invariant to be stateless, we'd probably resort to something like this: If you remove the If doing so makes Halmos competitively faster, then that's a tradeoff worth taking, whereas if there's no difference it's worth keeping both options open |
Is your feature request related to a problem? Please describe.
Per this merged foundry feature: foundry-rs/foundry#10253
We expect
targetContract(address(this));
to cause the fuzzer to use every function exposed by this as a handlerAnd we expect all invariants to be specified on
this
Describe the solution you'd like
An extremely common way of writing invariant tests uses Target Function, explicit functions that tell the fuzzer how to explore state
Source:
https://github.com/Recon-Fuzz/create-chimera-app (Recon)
https://github.com/perimetersec/arachne (PerimeterSec)
https://github.com/euler-xyz/euler-vault-kit/tree/master/src (Enigma Dark)
https://github.com/CodeHawks-Contests/2025-02-gamma/blob/main/test/fuzzing/echidna/CryticToFoundry.sol (Guardian Audits)
As it stands targetFunctions doesn't allow passing address(this)
This prevents these testing suites from being easily reusable with Halmos
Describe alternatives you've considered
This is an additional feature that makes Halmos competitive with Foundry, Echidna and Medusa
I'm unaware of any alternative that makes Halmos as powerful
Additional context
You can attempt running all tools on: https://github.com/Recon-Fuzz/create-chimera-app
Which is a template that is compatible with all of them
However, Halmos Invariant Testing will fail due to a lack of compatibility with
targetContract(address(this));
The text was updated successfully, but these errors were encountered: