Integrating EigenLayer Into Your Test Suite
Deploy the entire EigenLayer system + simulate slashing events in your test suite
Use cases
When building a protocol on top of EigenLayer, you may want to test how your system actually behaves with the actual EigenLayer system with integration tests, or you just want to test your system without caring too much about actual correct behavior of the EigenLayer side, in which case you’d end up mocking the EigenLayer system. But how do you know that your mocks don’t introduce some unexpected behavior, and do you really want to go through the process of setting up the entire EigenLayer system just so you can test your system?
Now you can have the best of both worlds with no extra work, by using the eigenlayer-fuzzing repo.
How to use
In this post we’ll use the renzo-fuzzing repo as an example of how to integrate the eigenlayer-fuzzing repo to setup your fuzzing/testing suite.
Note that this repo was built with Foundry and made to integrate with protocols using Foundry/Echidna/Medusa for invariant/unit testing.
1. Adding as submodule dependency
In the project you want to add the EigenLayer setup to, simply add it as a Foundry submodule dependency using the following command:
forge install Recon-Fuzz/eigenlayer-fuzzing
2. Add to system setup
In your project, inherit from the EigenLayerSystem
contract in your setup/test contract.
For the renzo-fuzzing example it’s been scaffolded with Recon so consists of a Setup
contract for where we define a setup
function for deploying the system in a manner compatible with Foundry and Echidna/Medusa:
Because the Renzo system deployment is quite extensive it’s been separated into a different contract (RenzoSetup
), where it inherits from EigenLayerSystem
allowing the deployEigenLayerLocal
function to be called in the Setup
contract.
3. Add targets for EigenLayer externalities
Now with both systems deployed and integrated with one another, all that remains is to add handler functions to our TargetFunctions
contract to allow the fuzzer to simulate externalities on EigenLayer that may effect the integrating system’s behavior.
These functions are also exposed by the EigenLayerSystem
contract as slashNative
and slashAVS
, and because we inherited from this in the Setup
contract, adding them to the Renzo fuzzing suite is just a matter of calling the function for a given user.
In the Renzo example the user is an OperatorDelegator
as they maintain all shares of deposits made in Renzo by individual users that get executed on EigenLayer.
Break Things
After adding the target functions you have a test suite ready to test your integrating system’s behavior using the actual EigenLayer implementation. Additionally, you have the ability to manipulate the EigenLayer state directly via the slashNative
and slashAVS
functions or define other potential externalities by calling the EigenLayer contracts directly to manipulate their state.
The only next step is to allow the fuzzer to run once you’ve defined target functions and properties and wait to see where something doesn’t behave as expected.