diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 09de9d27..cac9c728 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -58,13 +58,13 @@ jobs: run: forge soldeer install && yarn install - name: Compile contracts with Forge - run: forge build --sizes + run: forge build --sizes --skip Fuzzer #- name: Compile contracts with Hardhat # run: npx hardhat compile #################################################### - ### TESTS + ### CONCRETE TESTS #################################################### foundry-unit-tests: name: Foundry Unit-Tests @@ -134,8 +134,11 @@ jobs: - name: Run non-invariant tests run: forge test --summary --fail-fast --show-progress --mp 'test/smoke/**' - foundry-tests-invariants: - name: Foundry Invariants Tests + #################################################### + ### FUZZ TESTS + #################################################### + foundry-tests-invariants-OethARM: + name: Foundry Invariants Tests - OethARM runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 @@ -156,6 +159,22 @@ jobs: FOUNDRY_INVARIANT_FAIL_ON_REVERT=false \ FOUNDRY_MATCH_CONTRACT=FuzzerFoundry_OethARM \ forge test --summary --fail-fast --show-progress + + foundry-tests-invariants-OriginARM: + name: Foundry Invariants Tests - OriginARM + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: "v1.4.4" + + - name: Install Dependencies + run: forge soldeer install - name: Run invariant tests (OriginARM) run: | @@ -164,9 +183,47 @@ jobs: FOUNDRY_MATCH_CONTRACT=FuzzerFoundry_OriginARM \ forge test --summary --fail-fast --show-progress + foundry-tests-invariants-EthenaARM: + name: Foundry Invariants Tests - EthenaARM + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + with: + submodules: recursive + + - name: Install Foundry + uses: foundry-rs/foundry-toolchain@v1 + with: + version: "v1.4.4" + + - name: Install Dependencies + run: forge soldeer install + - name: Run invariant tests (EthenaARM) run: | FOUNDRY_PROFILE=ci \ FOUNDRY_INVARIANT_FAIL_ON_REVERT=true \ FOUNDRY_MATCH_CONTRACT=FuzzerFoundry_EthenaARM \ - forge test --summary --fail-fast --show-progress \ No newline at end of file + forge test --summary --fail-fast --show-progress + + - name: Setup Go + uses: actions/setup-go@v5 + with: + go-version: '1.21' + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.10' + + - name: Install Crytic Compile + run: pip install crytic-compile + + - name: Install Medusa from Source + run: go install github.com/crytic/medusa@latest + + - name: Run Medusa + working-directory: test/invariants/EthenaARM/ + run: medusa fuzz --timeout 1800 --seq-len 500 --fail-fast + + \ No newline at end of file diff --git a/.gitignore b/.gitignore index 7b4c4786..3f3e0acc 100644 --- a/.gitignore +++ b/.gitignore @@ -29,6 +29,7 @@ soldeer.lock # Coverage lcov.info* +crytic-export # Defender Actions dist @@ -37,4 +38,7 @@ cache_hardhat build/deployments-fork*.json # Reports. eg stats.html -*.html \ No newline at end of file +*.html + +# Other +.DS_Store \ No newline at end of file diff --git a/Makefile b/Makefile index efc30b67..19253495 100644 --- a/Makefile +++ b/Makefile @@ -15,8 +15,14 @@ install: clean: @rm -rf broadcast cache out -clean-all: - @rm -rf broadcast cache out dependencies node_modules soldeer.lock yarn.lock lcov.info lcov.info.pruned artifacts cache_hardhat +# Remove every "crytic-export" directory anywhere in the project +clean-crytic: + @find . -type d -name crytic-export -exec rm -rf '{}' + + +clean-all: + @rm -rf broadcast cache out dependencies node_modules soldeer.lock yarn.lock .lcov.info lcov.info pruned artifacts cache hardhat-node_modules + @$(MAKE) clean-crytic + gas: @forge test --gas-report diff --git a/test/invariants/EthenaARM/Base.sol b/test/invariants/EthenaARM/Base.sol index 66bbd10b..538b08ae 100644 --- a/test/invariants/EthenaARM/Base.sol +++ b/test/invariants/EthenaARM/Base.sol @@ -27,79 +27,79 @@ abstract contract Base_Test_ { /// --- CONTRACTS ////////////////////////////////////////////////////// // --- Main contracts --- - Proxy public armProxy; - Proxy public morphoMarketProxy; - EthenaARM public arm; - MockMorpho public morpho; - MorphoMarket public market; - EthenaUnstaker[] public unstakers; - uint256[] public unstakerIndices; + Proxy internal armProxy; + Proxy internal morphoMarketProxy; + EthenaARM internal arm; + MockMorpho internal morpho; + MorphoMarket internal market; + EthenaUnstaker[] internal unstakers; + uint256[] internal unstakerIndices; // --- Tokens --- - IERC20 public usde; - IStakedUSDe public susde; + IERC20 internal usde; + IStakedUSDe internal susde; // --- Utils --- - Vm public vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); + Vm internal vm = Vm(address(uint160(uint256(keccak256("hevm cheat code"))))); ////////////////////////////////////////////////////// /// --- USERS ////////////////////////////////////////////////////// // --- Users with roles --- - address public deployer; - address public governor; - address public operator; - address public treasury; + address internal deployer; + address internal governor; + address internal operator; + address internal treasury; // --- Regular users --- - address public alice; - address public bobby; - address public carol; - address public david; - address public elise; - address public frank; - address public grace; - address public harry; - address public dead; + address internal alice; + address internal bobby; + address internal carol; + address internal david; + address internal elise; + address internal frank; + address internal grace; + address internal harry; + address internal dead; // --- Group of users --- - address[] public makers; - address[] public traders; - mapping(address => uint256[]) public pendingRequests; + address[] internal makers; + address[] internal traders; + mapping(address => uint256[]) internal pendingRequests; ////////////////////////////////////////////////////// /// --- DEFAULT VALUES ////////////////////////////////////////////////////// - uint256 public constant MAKERS_COUNT = 3; - uint256 public constant TRADERS_COUNT = 3; - uint256 public constant UNSTAKERS_COUNT = 42; - uint256 public constant DEFAULT_CLAIM_DELAY = 10 minutes; - uint256 public constant DEFAULT_MIN_TOTAL_SUPPLY = 1e12; - uint256 public constant DEFAULT_ALLOCATE_THRESHOLD = 1e18; - uint256 public constant DEFAULT_MIN_SHARES_TO_REDEEM = 1e7; + uint256 internal constant MAKERS_COUNT = 3; + uint256 internal constant TRADERS_COUNT = 3; + uint256 internal constant UNSTAKERS_COUNT = 42; + uint256 internal constant DEFAULT_CLAIM_DELAY = 10 minutes; + uint256 internal constant DEFAULT_MIN_TOTAL_SUPPLY = 1e12; + uint256 internal constant DEFAULT_ALLOCATE_THRESHOLD = 1e18; + uint256 internal constant DEFAULT_MIN_SHARES_TO_REDEEM = 1e7; /// @notice Indicates if labels have been set in the Vm. - function isLabelAvailable() external view virtual returns (bool); - function isAssumeAvailable() external view virtual returns (bool); - function isConsoleAvailable() external view virtual returns (bool); + bool public isLabelAvailable; + bool public isAssumeAvailable; + bool public isConsoleAvailable; ////////////////////////////////////////////////////// /// --- GHOST VALUES ////////////////////////////////////////////////////// // --- USDe values --- - uint256 public sumUSDeSwapIn; - uint256 public sumUSDeSwapOut; - uint256 public sumUSDeUserDeposit; - uint256 public sumUSDeUserRedeem; - uint256 public sumUSDeUserRequest; - uint256 public sumUSDeBaseRedeem; - uint256 public sumUSDeFeesCollected; - uint256 public sumUSDeMarketDeposit; - uint256 public sumUSDeMarketWithdraw; - mapping(address => uint256) public mintedUSDe; + uint256 internal sumUSDeSwapIn; + uint256 internal sumUSDeSwapOut; + uint256 internal sumUSDeUserDeposit; + uint256 internal sumUSDeUserRedeem; + uint256 internal sumUSDeUserRequest; + uint256 internal sumUSDeBaseRedeem; + uint256 internal sumUSDeFeesCollected; + uint256 internal sumUSDeMarketDeposit; + uint256 internal sumUSDeMarketWithdraw; + mapping(address => uint256) internal mintedUSDe; // --- sUSDe values --- - uint256 public sumSUSDeSwapIn; - uint256 public sumSUSDeSwapOut; - uint256 public sumSUSDeBaseRedeem; + uint256 internal sumSUSDeSwapIn; + uint256 internal sumSUSDeSwapOut; + uint256 internal sumSUSDeBaseRedeem; } diff --git a/test/invariants/EthenaARM/FoundryFuzzer.sol b/test/invariants/EthenaARM/FuzzerFoundry_EthenaARM.sol similarity index 91% rename from test/invariants/EthenaARM/FoundryFuzzer.sol rename to test/invariants/EthenaARM/FuzzerFoundry_EthenaARM.sol index 03bca29f..6cd71e14 100644 --- a/test/invariants/EthenaARM/FoundryFuzzer.sol +++ b/test/invariants/EthenaARM/FuzzerFoundry_EthenaARM.sol @@ -15,15 +15,19 @@ import {StdAssertions} from "forge-std/StdAssertions.sol"; /// - Each invariant function represents a critical system property to maintain /// - Fuzzer will call targeted handlers randomly and check invariants after each call contract FuzzerFoundry_EthenaARM is Properties, StdInvariant, StdAssertions { - bool public constant override isLabelAvailable = true; - bool public constant override isAssumeAvailable = true; - bool public constant override isConsoleAvailable = true; - ////////////////////////////////////////////////////// /// --- SETUP ////////////////////////////////////////////////////// - function setUp() public override { - super.setUp(); + constructor() { + // --- Fuzzer configuration --- + isLabelAvailable = true; + isAssumeAvailable = true; + isConsoleAvailable = true; + } + + function setUp() public { + // --- Common setup --- + _setup(); // --- Setup Fuzzer target --- // Setup target @@ -87,7 +91,7 @@ contract FuzzerFoundry_EthenaARM is Properties, StdInvariant, StdAssertions { } function afterInvariant() public { - targetAfterAll(); - assertTrue(propertyAfterAll(), "Property After All failed"); + _targetAfterAll(); + assertTrue(_propertyAfterAll(), "Property After All failed"); } } diff --git a/test/invariants/EthenaARM/FuzzerMedusa_EthenaARM.sol b/test/invariants/EthenaARM/FuzzerMedusa_EthenaARM.sol new file mode 100644 index 00000000..d51ae753 --- /dev/null +++ b/test/invariants/EthenaARM/FuzzerMedusa_EthenaARM.sol @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: MIT +pragma solidity 0.8.23; + +// Test imports +import {Properties} from "./Properties.sol"; + +/// @title FuzzerFoundry +/// @notice Concrete fuzzing contract implementing Foundry's invariant testing framework. +/// @dev This contract configures and executes property-based testing: +/// - Inherits from Properties to access handler functions and properties +/// - Configures fuzzer targeting (contracts, selectors, senders) +/// - Implements invariant test functions that call property validators +/// - Each invariant function represents a critical system property to maintain +/// - Fuzzer will call targeted handlers randomly and check invariants after each call +contract FuzzerMedusa_EthenaARM is Properties { + ////////////////////////////////////////////////////// + /// --- SETUP + ////////////////////////////////////////////////////// + constructor() { + _setup(); + } +} diff --git a/test/invariants/EthenaARM/Properties.sol b/test/invariants/EthenaARM/Properties.sol index c29e5e97..ded0e232 100644 --- a/test/invariants/EthenaARM/Properties.sol +++ b/test/invariants/EthenaARM/Properties.sol @@ -195,12 +195,12 @@ abstract contract Properties is TargetFunctions { // ╔══════════════════════════════════════════════════════════════════════════════╗ // ║ ✦✦✦ AFTER ALL ✦✦✦ ║ // ╚══════════════════════════════════════════════════════════════════════════════╝ - function propertyAfterAll() public returns (bool) { + function _propertyAfterAll() internal returns (bool) { uint256 usdeBalance = usde.balanceOf(address(arm)); uint256 susdeBalance = susde.balanceOf(address(arm)); uint256 morphoBalance = morpho.balanceOf(address(arm)); uint256 armTotalAssets = arm.totalAssets(); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log("--- Final Balances ---"); console.log("ARM USDe balance:\t %18e", usdeBalance); console.log("ARM sUSDe balance:\t %18e", susdeBalance); @@ -214,7 +214,7 @@ abstract contract Properties is TargetFunctions { uint256 totalMinted = mintedUSDe[user]; uint256 userBalance = usde.balanceOf(user); if (!Math.approxGteAbs(userBalance, totalMinted, 1e1)) { - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log(">>> Property After All failed for user %s:", vm.getLabel(user)); console.log(" - User USDe balance: %18e", userBalance); console.log(" - Total minted USDe: %18e", totalMinted); diff --git a/test/invariants/EthenaARM/Setup.sol b/test/invariants/EthenaARM/Setup.sol index 6dcd59a9..91713b8a 100644 --- a/test/invariants/EthenaARM/Setup.sol +++ b/test/invariants/EthenaARM/Setup.sol @@ -26,7 +26,7 @@ abstract contract Setup is Base_Test_ { ////////////////////////////////////////////////////// /// --- SETUP ////////////////////////////////////////////////////// - function setUp() public virtual { + function _setup() internal virtual { // 1. Setup a realistic test environnement. _setUpRealisticEnvironnement(); @@ -159,7 +159,7 @@ abstract contract Setup is Base_Test_ { function _labelAll() internal virtual { // This only works with Foundry's Vm.label feature. - if (!this.isLabelAvailable()) return; + if (!isLabelAvailable) return; // --- Proxies --- vm.label(address(armProxy), "Proxy EthenaARM"); @@ -292,7 +292,7 @@ abstract contract Setup is Base_Test_ { function assume(bool condition) internal returns (bool returnEarly) { if (!condition) { - if (this.isAssumeAvailable()) vm.assume(false); + if (isAssumeAvailable) vm.assume(false); else returnEarly = true; } } diff --git a/test/invariants/EthenaARM/TargetFunctions.sol b/test/invariants/EthenaARM/TargetFunctions.sol index 17d187a3..be4d1034 100644 --- a/test/invariants/EthenaARM/TargetFunctions.sol +++ b/test/invariants/EthenaARM/TargetFunctions.sol @@ -81,7 +81,7 @@ abstract contract TargetFunctions is Setup, StdUtils { vm.prank(user); uint256 shares = arm.deposit(amount, user); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( ">>> ARM Deposit:\t %s deposited %18e USDe\t and received %18e ARM shares", vm.getLabel(user), @@ -119,7 +119,7 @@ abstract contract TargetFunctions is Setup, StdUtils { (uint256 requestId, uint256 amount) = arm.requestRedeem(shareAmount); pendingRequests[user].push(requestId); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( string( abi.encodePacked( @@ -170,7 +170,7 @@ abstract contract TargetFunctions is Setup, StdUtils { // Fast forward time if needed if (block.timestamp < claimTimestamp) { - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( StdStyle.yellow( string( @@ -193,7 +193,7 @@ abstract contract TargetFunctions is Setup, StdUtils { vm.prank(user); uint256 amount = arm.claimRedeem(requestId); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( string( abi.encodePacked( @@ -220,7 +220,7 @@ abstract contract TargetFunctions is Setup, StdUtils { vm.prank(operator); arm.setARMBuffer(pct * 1e16); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log(">>> ARM Buffer:\t Governor set ARM buffer to %s%", pct); } } @@ -245,7 +245,7 @@ abstract contract TargetFunctions is Setup, StdUtils { arm.setActiveMarket(targetMarket); uint256 balanceAfter = usde.balanceOf(address(arm)); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( ">>> ARM SetMarket:\t Governor set active market to %s", isActive ? "Morpho Market" : "No active market" ); @@ -265,7 +265,7 @@ abstract contract TargetFunctions is Setup, StdUtils { (int256 targetLiquidityDelta, int256 actualLiquidityDelta) = arm.allocate(); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( string( abi.encodePacked( @@ -298,7 +298,7 @@ abstract contract TargetFunctions is Setup, StdUtils { vm.prank(operator); arm.setPrices(buyPrice, sellPrice); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( ">>> ARM SetPrices:\t Governor set buy price to %36e\t sell price to %36e\t cross price to %36e", buyPrice, @@ -325,7 +325,7 @@ abstract contract TargetFunctions is Setup, StdUtils { vm.prank(governor); arm.setCrossPrice(crossPrice); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log(">>> ARM SetCPrice:\t Governor set cross price to %36e", crossPrice); } } @@ -377,7 +377,7 @@ abstract contract TargetFunctions is Setup, StdUtils { uint256[] memory obtained = arm.swapExactTokensForTokens(tokenIn, tokenOut, amountIn, 0, user); vm.stopPrank(); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( string( abi.encodePacked( @@ -454,7 +454,7 @@ abstract contract TargetFunctions is Setup, StdUtils { uint256[] memory obtained = arm.swapTokensForExactTokens(tokenIn, tokenOut, amountOut, type(uint256).max, user); vm.stopPrank(); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( string( abi.encodePacked( @@ -489,7 +489,7 @@ abstract contract TargetFunctions is Setup, StdUtils { uint256 feesCollected = arm.collectFees(); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log(">>> ARM Collect:\t Governor collected %18e USDe in fees", feesCollected); } require(feesCollected == feesAccrued, "Fees collected mismatch"); @@ -512,7 +512,7 @@ abstract contract TargetFunctions is Setup, StdUtils { vm.prank(governor); arm.setFee(fee * 100); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log(">>> ARM SetFees:\t Governor set ARM fee from %s% to %s%", oldFee / 100, fee); } @@ -535,7 +535,7 @@ abstract contract TargetFunctions is Setup, StdUtils { // Ensure time delay has passed uint32 lastRequestTimestamp = arm.lastRequestTimestamp(); if (block.timestamp < lastRequestTimestamp + 3 hours) { - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( StdStyle.yellow( string( @@ -558,7 +558,7 @@ abstract contract TargetFunctions is Setup, StdUtils { unstakerIndices.push(nextIndex); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( ">>> ARM ReqBaseW:\t Operator requested base withdrawal of %18e sUSDe underlying, using unstakers #%s", amount, @@ -583,7 +583,7 @@ abstract contract TargetFunctions is Setup, StdUtils { // Fast forward time if needed if (block.timestamp < endTimestamp) { - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( StdStyle.yellow( string( @@ -608,7 +608,7 @@ abstract contract TargetFunctions is Setup, StdUtils { unstakerIndices[randomAddressIndex % unstakerIndices.length] = unstakerIndices[unstakerIndices.length - 1]; unstakerIndices.pop(); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( string( abi.encodePacked( @@ -641,7 +641,7 @@ abstract contract TargetFunctions is Setup, StdUtils { vm.prank(grace); uint256 shares = susde.deposit(amount, grace); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( ">>> sUSDe Deposit:\t Grace deposited %18e USDe\t and received %18e sUSDe shares", amount, shares ); @@ -661,7 +661,7 @@ abstract contract TargetFunctions is Setup, StdUtils { // Cooldown shares as grace vm.prank(grace); uint256 amount = susde.cooldownShares(shareAmount); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( ">>> sUSDe Cooldown:\t Grace cooled down %18e sUSDe shares\t for %18e USDe underlying", shareAmount, @@ -679,7 +679,7 @@ abstract contract TargetFunctions is Setup, StdUtils { // Fast forward to after cooldown end if needed if (block.timestamp < cooldown.cooldownEnd) { - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( StdStyle.yellow( string( @@ -701,7 +701,7 @@ abstract contract TargetFunctions is Setup, StdUtils { vm.prank(grace); susde.unstake(grace); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( ">>> sUSDe Unstake:\t Grace unstaked %18e USDe underlying after cooldown", cooldown.underlyingAmount ); @@ -714,7 +714,7 @@ abstract contract TargetFunctions is Setup, StdUtils { uint256 lastDistribution = susde.lastDistributionTimestamp(); if (block.timestamp < 8 hours + lastDistribution) { // Fast forward time to allow rewards distribution - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( StdStyle.yellow( string( @@ -740,7 +740,7 @@ abstract contract TargetFunctions is Setup, StdUtils { vm.prank(governor); susde.transferInRewards(rewards); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log(">>> sUSDe Rewards:\t Governor transferred in %18e USDe as rewards, bps: %d", rewards, bps); } } @@ -763,7 +763,7 @@ abstract contract TargetFunctions is Setup, StdUtils { vm.prank(harry); uint256 shares = morpho.deposit(amount, harry); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( ">>> Morpho Deposit:\t Harry deposited %18e USDe\t and received %18e Morpho shares", amount, shares ); @@ -787,7 +787,7 @@ abstract contract TargetFunctions is Setup, StdUtils { // Withdraw as harry vm.prank(harry); uint256 shares = morpho.withdraw(amount, harry, harry); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log( ">>> Morpho Withdraw:\t Harry withdrew %18e Morpho shares\t for %18e USDe underlying", shares, amount ); @@ -802,7 +802,7 @@ abstract contract TargetFunctions is Setup, StdUtils { uint256 rewards = (balance * bps) / 10_000; MockERC20(address(usde)).mint(address(morpho), rewards); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log(">>> Morpho Rewards:\t Transferred in %18e USDe as rewards, bps: %d", rewards, bps); } } @@ -812,12 +812,12 @@ abstract contract TargetFunctions is Setup, StdUtils { morpho.setUtilizationRate(pct * 1e16); - if (this.isConsoleAvailable()) { + if (isConsoleAvailable) { console.log(">>> Morpho UseRate:\t Governor set utilization rate to %s%", pct); } } - function targetAfterAll() public { + function _targetAfterAll() internal { // In this function, we will simulate shutting down the ARM. This involves letting all users redeem their funds. // This is important to ensure that the ARM can handle a complete withdrawal scenario without issues. // This involves: diff --git a/test/invariants/EthenaARM/helpers/Test.sol b/test/invariants/EthenaARM/helpers/Test.sol index 15e4f93c..983b4bab 100644 --- a/test/invariants/EthenaARM/helpers/Test.sol +++ b/test/invariants/EthenaARM/helpers/Test.sol @@ -3,7 +3,7 @@ pragma solidity 0.8.23; import {Test} from "forge-std/Test.sol"; -import {FuzzerFoundry_EthenaARM} from "test/invariants/EthenaARM/FoundryFuzzer.sol"; +import {FuzzerFoundry_EthenaARM} from "test/invariants/EthenaARM/FuzzerFoundry_EthenaARM.sol"; contract Unit_Ethena_replay is Test { FuzzerFoundry_EthenaARM f; diff --git a/test/invariants/EthenaARM/medusa.json b/test/invariants/EthenaARM/medusa.json new file mode 100644 index 00000000..f939beb8 --- /dev/null +++ b/test/invariants/EthenaARM/medusa.json @@ -0,0 +1,108 @@ +{ + "fuzzing": { + "workers": 10, + "workerResetLimit": 50, + "timeout": 0, + "testLimit": 0, + "shrinkLimit": 5000, + "callSequenceLength": 200, + "pruneFrequency": 5, + "corpusDirectory": "", + "coverageEnabled": true, + "coverageFormats": [ + "html", + "lcov" + ], + "coverageExclusions": [], + "revertReporterEnabled": false, + "targetContracts": [ + "FuzzerMedusa_EthenaARM" + ], + "predeployedContracts": {}, + "targetContractsBalances": [], + "constructorArgs": {}, + "deployerAddress": "0x30000", + "senderAddresses": [ + "0x10000", + "0x20000", + "0x30000" + ], + "blockNumberDelayMax": 60480, + "blockTimestampDelayMax": 604800, + "transactionGasLimit": 12500000, + "testing": { + "stopOnFailedTest": true, + "stopOnFailedContractMatching": false, + "stopOnNoTests": true, + "testAllContracts": false, + "testViewMethods": true, + "verbosity": 2, + "assertionTesting": { + "enabled": false, + "panicCodeConfig": { + "failOnCompilerInsertedPanic": true, + "failOnAssertion": true, + "failOnArithmeticUnderflow": true, + "failOnDivideByZero": true, + "failOnEnumTypeConversionOutOfBounds": true, + "failOnIncorrectStorageAccess": true, + "failOnPopEmptyArray": true, + "failOnOutOfBoundsArrayAccess": true, + "failOnAllocateTooMuchMemory": true, + "failOnCallUninitializedVariable": true + } + }, + "propertyTesting": { + "enabled": true, + "testPrefixes": [ + "property" + ] + }, + "optimizationTesting": { + "enabled": false, + "testPrefixes": [ + "optimize_" + ] + }, + "targetFunctionSignatures": [], + "excludeFunctionSignatures": [ + "FuzzerMedusa_EthenaARM.isLabelAvailable()", + "FuzzerMedusa_EthenaARM.isAssumeAvailable()", + "FuzzerMedusa_EthenaARM.isConsoleAvailable()" + ] + }, + "chainConfig": { + "codeSizeCheckDisabled": true, + "cheatCodes": { + "cheatCodesEnabled": true, + "enableFFI": false + }, + "skipAccountChecks": true, + "forkConfig": { + "forkModeEnabled": false, + "rpcUrl": "", + "rpcBlock": 1, + "poolSize": 20 + } + } + }, + "compilation": { + "platform": "crytic-compile", + "platformConfig": { + "target": ".", + "solcVersion": "", + "exportDirectory": "", + "args": [] + } + }, + "slither": { + "useSlither": true, + "cachePath": "", + "args": [] + }, + "logging": { + "level": "trace", + "logDirectory": "", + "noColor": false + } +} \ No newline at end of file