-
Notifications
You must be signed in to change notification settings - Fork 4
New issue
Have a question about this project? Sign up for a free GitHub 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
Invariant testing campaign #29
Merged
Merged
Conversation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
naddison36
approved these changes
Oct 16, 2024
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow, this is amazing
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Goal
This PR aims to bring invariant testing to ensure a better test coverage of
LidoARM.sol
contract.What is Invariant testing
In stateless fuzzing test that are already implemented (in swap), a single function is tested with multiple random inputs. But after each call the state is reverted.
In contract, invariant testing can be seen as stateful fuzzing test as it evaluates a group of unchanging conditions against randomized sequences of predefined contract functions.
The system checks these invariant conditions after each function call.This method is particularly effective at uncovering flaws in protocol logic. By using randomized function sequences and fuzzy inputs, invariant testing can reveal faulty assumptions and errors in complex protocol states and edge cases that might otherwise go unnoticed.
Technical description
List of called functions:
During the invariant tests, multiple random function will be called, here is the list of function that can be called:
deposit()
requestRedeem()
claimRedeem()
swapExactTokensForTokens()
swapTokensForExactTokens()
setPrices()
setCrossPrice()
collectFees()
setFees()
requestStETHWithdrawalForETH()
claimStETHWithdrawalForWETH()
External functions
donateStETH()
donateWETH()
Custom probability distribution
During invariant testing process, by default Foundry will call randomly functions, with the same exact probability.
However, sometime this doesn't make sense and it doesn't represent what will happen once contract will be deployed.
For example
deposit()
orswapExactTokensForTokens()
will be called way more often thansetFees()
. To overcome this problem, we introduce Custom Probability Distribution.Instead of Foundry directly calling random function, Foundry will be forced to call
DistributionHandler.sol
which only have a single functiondistributorEntryPoint()
. Which will in turn callentryPoint()
of the underlying handler with a custom probability. ThisentryPoint()
will in turn one of the function implemented in the handler with a custom probability. This gives us much greater granularity!Mocks
Invariant testing performs a lot of call, so in order to make it faster, mocks are implemented instead of forking mainnet.
Mocks are used for:
To simulate STETH rounding issue on transfer, the mock randomly transfer -0 or -1 wei.
arm-oeth/test/invariants/mocks/MockSTETH.sol
Lines 35 to 46 in 257468e
To simulate Lido Withdraw and make it easier to work with, there is no finalization process, i.e. as soon as the request is done, the ARM can withdraw it and will receive ETH.
arm-oeth/test/invariants/mocks/MockLidoWithdraw.sol
Lines 80 to 82 in 257468e
Invariants assertions
At the end of each call, all the invariants will be asserted. Here is a non-exhaustive list of invariants used: