integration-test-writer
Write Solidity integration tests for EigenLayer contracts. Use when the user asks to write integration tests, test user flows, test cross-contract interactions, or test upgrade scenarios. Follows project conventions with User/AVS actors and numbered action steps.
Install
mkdir -p .claude/skills/integration-test-writer && curl -L -o skill.zip "https://mcp.directory/api/skills/download/7656" && unzip -o skill.zip -d .claude/skills/integration-test-writer && rm skill.zipInstalls to .claude/skills/integration-test-writer
About this skill
Integration Test Writer
Write comprehensive integration tests for EigenLayer Solidity contracts following the project's established conventions.
Overview
Integration tests orchestrate the deployment of all EigenLayer core contracts to test high-level user flows across multiple contracts. There are three test modes:
- Local Integration Tests - Deploy fresh contracts and test user flows
- Fork Tests - Fork mainnet, upgrade all contracts to latest implementations, then run the integration test suite
- Upgrade Tests - Fork mainnet, perform actions on OLD contracts, then upgrade and verify compatibility
Test Function Signature
All integration test functions MUST:
- Be named
testFuzz_action1_action2_...describing the flow - Take
uint24 _random(or_r) as the only parameter - this seeds randomness - Use the
rand(_random)modifier to initialize the random seed
function testFuzz_deposit_delegate_queue_complete(uint24 _random) public rand(_random) {
// Test implementation
}
The rand() modifier initializes the test's random seed, which is used by helper functions like _newRandomStaker() to generate deterministic random values for reproducible tests.
Test File Locations
| Type | Location |
|---|---|
| Normal integration tests | src/test/integration/tests/ |
| Upgrade tests | src/test/integration/tests/upgrade/ |
| Check functions | src/test/integration/IntegrationChecks.t.sol |
| Multichain checks | src/test/integration/MultichainIntegrationChecks.t.sol |
Core Principles
1. All Actions Must Be Called Through User Contracts
Never call contracts directly. Use the User or AVS actor contracts:
// ✅ CORRECT - Actions through User/AVS
staker.depositIntoEigenlayer(strategies, tokenBalances);
operator.delegateTo(operator);
avs.createOperatorSet(strategies);
// ❌ WRONG - Direct contract calls
strategyManager.depositIntoStrategy(...);
delegationManager.delegateTo(...);
2. Every Action Must Be Followed By a Check
After each numbered action, verify state changes using check_* functions from IntegrationChecks.t.sol:
// 1. Deposit Into Strategies
staker.depositIntoEigenlayer(strategies, tokenBalances);
check_Deposit_State(staker, strategies, shares);
// 2. Delegate to an operator
staker.delegateTo(operator);
check_Delegation_State(staker, operator, strategies, shares);
3. Actions Must Be Numbered
Use comments to number each action step for clarity:
// 1. Deposit Into Strategies
staker.depositIntoEigenlayer(strategies, tokenBalances);
check_Deposit_State(staker, strategies, shares);
// 2. Delegate to an operator
staker.delegateTo(operator);
check_Delegation_State(staker, operator, strategies, shares);
// 3. Queue Withdrawals
Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares);
check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots);
User Types
User (Staker/Operator)
Located in src/test/integration/users/User.t.sol. A User can act as both a staker AND an operator.
Key methods:
depositIntoEigenlayer(strategies, tokenBalances)- Deposit tokensdelegateTo(operator)- Delegate to an operatorregisterAsOperator()- Register as an operatorqueueWithdrawals(strategies, shares)- Queue withdrawalscompleteWithdrawalAsTokens(withdrawal)/completeWithdrawalAsShares(withdrawal)- Complete withdrawalsregisterForOperatorSet(operatorSet)- Register for an operator setmodifyAllocations(params)- Allocate magnitude to operator setsstartValidators()/verifyWithdrawalCredentials(validators)- Native ETH stakingstartCheckpoint()/completeCheckpoint()- Checkpoint EigenPod
AVS
Located in src/test/integration/users/AVS.t.sol. Represents an AVS that creates operator sets and slashes operators.
Key methods:
createOperatorSet(strategies)- Create an operator setcreateRedistributingOperatorSets(strategies, recipients)- Create redistributing operator setsslashOperator(params)- Slash an operatorupdateSlasher(operatorSetId, slasher)- Update the slasher for an operator set
Test Structure
Normal Integration Test
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "src/test/integration/IntegrationChecks.t.sol";
/// @notice Base contract for shared setup across test variants
contract Integration_FlowName_Base is IntegrationCheckUtils {
using ArrayLib for *;
// Declare state used across tests
AVS avs;
OperatorSet operatorSet;
User operator;
User staker;
IStrategy[] strategies;
uint[] initTokenBalances;
uint[] initDepositShares;
/// @dev Setup state used across all test functions
function _init() internal virtual override {
_configAssetTypes(HOLDS_LST | HOLDS_ETH); // Configure asset types
// Create actors
(staker, strategies, initTokenBalances) = _newRandomStaker();
(operator,,) = _newRandomOperator();
(avs,) = _newRandomAVS();
// 1. Deposit into strategies
staker.depositIntoEigenlayer(strategies, initTokenBalances);
initDepositShares = _calculateExpectedShares(strategies, initTokenBalances);
check_Deposit_State(staker, strategies, initDepositShares);
// 2. Delegate staker to operator
staker.delegateTo(operator);
check_Delegation_State(staker, operator, strategies, initDepositShares);
// 3. Create operator set and register
operatorSet = avs.createOperatorSet(strategies);
operator.registerForOperatorSet(operatorSet);
check_Registration_State_NoAllocation(operator, operatorSet, allStrats);
}
}
/// @notice Test contract for specific flow variant
contract Integration_FlowName_Variant is Integration_FlowName_Base {
/// @dev All test functions must:
/// 1. Be named testFuzz_action1_action2_...
/// 2. Take uint24 _r as parameter (seeds randomness)
/// 3. Use rand(_r) modifier
function testFuzz_action1_action2(uint24 _r) public rand(_r) {
// 4. Next action
// ... action ...
// ... check ...
// 5. Another action
// ... action ...
// ... check ...
}
}
Upgrade Test
Upgrade tests verify that upgrades correctly handle pre-upgrade state.
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.27;
import "src/test/integration/UpgradeTest.t.sol";
contract Integration_Upgrade_FeatureName is UpgradeTest {
User staker;
IStrategy[] strategies;
uint[] tokenBalances;
function _init() internal override {
// Pre-upgrade setup - NO check_ functions here!
(staker, strategies, tokenBalances) = _newRandomStaker();
staker.depositIntoEigenlayer(strategies, tokenBalances);
// ... more pre-upgrade actions WITHOUT checks
}
function testFuzz_upgrade_scenario(uint24 _r) public rand(_r) {
/// Pre-upgrade actions (no checks - old contracts)
Withdrawal[] memory withdrawals = staker.queueWithdrawals(strategies, shares);
/// Upgrade to new contracts
_upgradeEigenLayerContracts();
/// Post-upgrade actions WITH checks
_rollBlocksForCompleteWithdrawals(withdrawals);
for (uint i = 0; i < withdrawals.length; i++) {
staker.completeWithdrawalAsShares(withdrawals[i]);
check_Withdrawal_AsShares_State(staker, operator, withdrawals[i], strategies, shares);
}
}
}
Important for Upgrade Tests:
- Pre-upgrade actions should NOT have
check_*functions (old contracts have different invariants) - Call
_upgradeEigenLayerContracts()to upgrade to new contracts - Post-upgrade actions SHOULD have
check_*functions - Only run on mainnet forks:
env FOUNDRY_PROFILE=forktest forge t --mc Integration_Upgrade
Check Functions
All state verification should be in IntegrationChecks.t.sol. There are two types:
1. check_* Functions
High-level state checks that verify multiple invariants after an action:
check_Deposit_State(staker, strategies, shares);
check_Delegation_State(staker, operator, strategies, shares);
check_QueuedWithdrawal_State(staker, operator, strategies, shares, withdrawableShares, withdrawals, withdrawalRoots);
check_Withdrawal_AsTokens_State(staker, operator, withdrawal, strategies, shares, tokens, expectedTokens);
2. assert_Snap_* Functions
Time-machine assertions that compare state before/after an action:
assert_Snap_Added_Staker_DepositShares(staker, strategy, amount, "error message");
assert_Snap_Removed_Staker_WithdrawableShares(staker, strategy, amount, "error message");
assert_Snap_Unchanged_Staker_DepositShares(staker, "error message");
Adding New Checks
If a check doesn't exist, add it to IntegrationChecks.t.sol:
function check_NewAction_State(
User staker,
IStrategy[] memory strategies,
uint[] memory expectedValues
) internal {
// Use assert_Snap_* for before/after comparisons
assert_Snap_Added_Staker_DepositShares(
staker, strategies[0], expectedValues[0], "should have added shares"
);
// Or use regular assertions for absolute checks
assertEq(
someContract.getValue(address(staker)),
expectedValue,
"value should match expected"
);
}
Randomness and Configuration
The rand(_r) Modifier
Every test function takes a uint24 _r parameter and uses the rand(_r) modifier:
function testFuzz_deposit_delegate(uint24 _r) public rand(_r) {
// _r seeds all random generation in this test
// This makes tests reproducible - same _r = same test execution
}
The rand() modifier initializes the random seed used by all _newRandom* helper functions. This ensures:
- Reproducibility: Same see
Content truncated.
More by Layr-Labs
View all skills by Layr-Labs →You might also like
flutter-development
aj-geddes
Build beautiful cross-platform mobile apps with Flutter and Dart. Covers widgets, state management with Provider/BLoC, navigation, API integration, and material design.
drawio-diagrams-enhanced
jgtolentino
Create professional draw.io (diagrams.net) diagrams in XML format (.drawio files) with integrated PMP/PMBOK methodologies, extensive visual asset libraries, and industry-standard professional templates. Use this skill when users ask to create flowcharts, swimlane diagrams, cross-functional flowcharts, org charts, network diagrams, UML diagrams, BPMN, project management diagrams (WBS, Gantt, PERT, RACI), risk matrices, stakeholder maps, or any other visual diagram in draw.io format. This skill includes access to custom shape libraries for icons, clipart, and professional symbols.
ui-ux-pro-max
nextlevelbuilder
"UI/UX design intelligence. 50 styles, 21 palettes, 50 font pairings, 20 charts, 8 stacks (React, Next.js, Vue, Svelte, SwiftUI, React Native, Flutter, Tailwind). Actions: plan, build, create, design, implement, review, fix, improve, optimize, enhance, refactor, check UI/UX code. Projects: website, landing page, dashboard, admin panel, e-commerce, SaaS, portfolio, blog, mobile app, .html, .tsx, .vue, .svelte. Elements: button, modal, navbar, sidebar, card, table, form, chart. Styles: glassmorphism, claymorphism, minimalism, brutalism, neumorphism, bento grid, dark mode, responsive, skeuomorphism, flat design. Topics: color palette, accessibility, animation, layout, typography, font pairing, spacing, hover, shadow, gradient."
godot
bfollington
This skill should be used when working on Godot Engine projects. It provides specialized knowledge of Godot's file formats (.gd, .tscn, .tres), architecture patterns (component-based, signal-driven, resource-based), common pitfalls, validation tools, code templates, and CLI workflows. The `godot` command is available for running the game, validating scripts, importing resources, and exporting builds. Use this skill for tasks involving Godot game development, debugging scene/resource files, implementing game systems, or creating new Godot components.
nano-banana-pro
garg-aayush
Generate and edit images using Google's Nano Banana Pro (Gemini 3 Pro Image) API. Use when the user asks to generate, create, edit, modify, change, alter, or update images. Also use when user references an existing image file and asks to modify it in any way (e.g., "modify this image", "change the background", "replace X with Y"). Supports both text-to-image generation and image-to-image editing with configurable resolution (1K default, 2K, or 4K for high resolution). DO NOT read the image file first - use this skill directly with the --input-image parameter.
fastapi-templates
wshobson
Create production-ready FastAPI projects with async patterns, dependency injection, and comprehensive error handling. Use when building new FastAPI applications or setting up backend API projects.
Related MCP Servers
Browse all serversUnlock powerful Excel automation: read/write Excel files, create sheets, and automate workflows with seamless integratio
Simplify email marketing and automation with Migadu's API integration for bulk mailbox, alias, and autoresponder managem
Connect Obsidian vaults for natural language queries and secure note updates with seamless Obsidian integration.
Learn how to use Python to read a file and manipulate local files safely through the Filesystem API.
Boost your AI code assistant with Context7: inject real-time API documentation from OpenAPI specification sources into y
Boost productivity with Task Master: an AI-powered tool for project management and agile development workflows, integrat
Stay ahead of the MCP ecosystem
Get weekly updates on new skills and servers.