Skip to content

Commit

Permalink
chore: barebones medusa setup from boilerplate
Browse files Browse the repository at this point in the history
  • Loading branch information
0xteddybear committed Oct 24, 2024
1 parent fdb548e commit 31f6095
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 1 deletion.
23 changes: 23 additions & 0 deletions .github/workflows/medusa.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
name: CI

on: [push]

jobs:
medusa-tests:
name: Medusa Test
runs-on: ubuntu-latest
container: ghcr.io/defi-wonderland/eth-security-toolbox-ci:dev

steps:
- name: Checkout repository
uses: actions/checkout@v4
with:
submodules: recursive

- name: Install dependencies
working-directory: ./packages/contracts-bedrock
run: yarn --frozen-lockfile --network-concurrency 1

- name: Run Medusa
working-directory: ./packages/contracts-bedrock
run: medusa fuzz --test-limit 200000
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ The fact that the state root is not writeable in the lifetime of the contract is
## mutate the state root
Idea for this is to initialize the BalanceClaimer in the campaign constructor with either

- [ ] an empty state root (for ...purity? ie allowing the fuzzer choose the inputs with the greatest variability)
- [ ] an empty state root (for ...purity? ie allowing the fuzzer choose the inputs with the greatest variability)
- [ ] pre-filled state root (to cover code faster) and set of valid claims, with the downside of calls creating

and have handlers to _add_ valid claims to the set, overwriting the state root
Expand All @@ -36,6 +36,8 @@ this would involve
- [ ] have a modifier (and an extra param of fuzzed input in every handler/property check) which will be used to initialize the state root on the first call
- [ ] have all handlers afterwards only process claims (valid or not, obviously) and not create new ones

This has the upside of being identical to the production setup, but would yield uglier code and potentially have worse pseudorandom input since we would be having all the state as fields of structs in arrays

# nice to haves
- [ ] use tokens' actual bytecode in the fuzzing campaign

Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;

import {BalanceClaimerGuidedHandlers} from './handlers/guided/BalanceClaimer.t.sol';
import {BalanceClaimerUnguidedHandlers} from './handlers/unguided/BalanceClaimer.t.sol';
import {BalanceClaimerProperties} from './properties/BalanceClaimer.t.sol';

contract FuzzTest is BalanceClaimerGuidedHandlers, BalanceClaimerUnguidedHandlers, BalanceClaimerProperties {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;

import {BalanceClaimerSetup} from '../../setup/BalanceClaimer.t.sol';

contract BalanceClaimerGuidedHandlers is BalanceClaimerSetup {
function handler_fooGuided() external {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;

import {BalanceClaimerSetup} from '../../setup/BalanceClaimer.t.sol';

contract BalanceClaimerUnguidedHandlers is BalanceClaimerSetup {
/// @custom:property-id
/// @custom:property
function handler_fooUnguided(address _caller, string memory _newGreeting) external {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;

import {BalanceClaimerSetup} from '../setup/BalanceClaimer.t.sol';

contract BalanceClaimerProperties is BalanceClaimerSetup {
/// @custom:property-id 1
/// @custom:property foo
function property_foo() external view {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity 0.8.15;

import "forge-std/console.sol";

import {BalanceClaimer} from "contracts/L1/winddown/BalanceClaimer.sol";
import {OptimismPortal} from "contracts/L1/OptimismPortal.sol";
import {L1StandardBridge} from "contracts/L1/L1StandardBridge.sol";
import {L1ChugSplashProxy} from "contracts/legacy/L1ChugSplashProxy.sol";
import {L2OutputOracle} from "contracts/L1/L2OutputOracle.sol";
import {SystemConfig} from "contracts/L1/SystemConfig.sol";
import {Proxy} from "contracts/universal/Proxy.sol";
import {WinddownConstants} from "scripts/winddown-upgrade/WinddownConstants.sol";

import {CommonBase} from "forge-std/Base.sol";

contract BalanceClaimerSetup is CommonBase {
L1StandardBridge internal l1StandardBridge;
OptimismPortal internal optimismPortal;
BalanceClaimer internal balanceClaimer;

constructor() {
// _targetContract = new BalanceClaimer();
// optimismPortal = new OptimimismPortal({
// _l2Oracle: L2OutputOracle(address(0)),
// _guardian: address(0),
// _config: SystemConfig(address(0))},
// balanceClaimer: balanceClaimer);
// l1StandardBridge = new L1StandardBridge(address(0), address(balanceClaimer));
// Get the proxies for L1StandardBridge and OptimismPortal
L1ChugSplashProxy l1StandardBridgeProxy =
L1ChugSplashProxy(payable(address(WinddownConstants.L1_STANDARD_BRIDGE_PROXY)));
Proxy optimismPortalProxy = Proxy(payable(address(WinddownConstants.OPTIMISM_PORTAL_PROXY)));

// Deploy BalanceClaimer proxy
Proxy balanceClaimerProxy = new Proxy(address(this));

// Deploy BalanceClaimer implementation
BalanceClaimer balanceClaimerImpl = new BalanceClaimer();

// Set BalanceClaimer implementation
balanceClaimerProxy.upgradeToAndCall(
address(balanceClaimerImpl),
abi.encodeWithSelector(
balanceClaimerImpl.initialize.selector,
address(optimismPortalProxy),
address(l1StandardBridgeProxy),
WinddownConstants.MERKLE_ROOT
)
);

optimismPortal = OptimismPortal(payable(optimismPortalProxy));
l1StandardBridge = L1StandardBridge(payable(l1StandardBridgeProxy));
balanceClaimer = BalanceClaimer(address(balanceClaimerProxy));
}

/// @custom:prop-id 0
/// @custom:prop sanity checks for setup
function property_setup() external {
assert(address(l1StandardBridge.BALANCE_CLAIMER()) == address(balanceClaimer));
assert(address(optimismPortal.BALANCE_CLAIMER()) == address(balanceClaimer));
assert(address(balanceClaimer.ethBalanceWithdrawer()) == address(l1StandardBridge));
assert(address(balanceClaimer.erc20BalanceWithdrawer()) == address(optimismPortal));
assert(balanceClaimer.root() == bytes32(0));
}
}
5 changes: 5 additions & 0 deletions packages/contracts-bedrock/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ fs_permissions = [
{ 'access'='read-write', 'path'='./.resource-metering.csv' },
]

[profile.medusa]
src='contracts/test/invariants/balance-claimer'
test='contracts/test/invariants/balance-claimer'
script='contracts/test/invariants/balance-claimer'

[profile.ci]
fuzz_runs = 512

Expand Down
89 changes: 89 additions & 0 deletions packages/contracts-bedrock/medusa.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
{
"fuzzing": {
"workers": 10,
"workerResetLimit": 50,
"timeout": 0,
"testLimit": 0,
"shrinkLimit": 5000,
"callSequenceLength": 100,
"corpusDirectory": "",
"coverageEnabled": true,
"coverageFormats": [
"html",
"lcov"
],
"targetContracts": ["FuzzTest"],
"predeployedContracts": {},
"targetContractsBalances": [],
"constructorArgs": {},
"deployerAddress": "0x30000",
"senderAddresses": [
"0x10000",
"0x20000",
"0x30000"
],
"blockNumberDelayMax": 60480,
"blockTimestampDelayMax": 604800,
"blockGasLimit": 125000000,
"transactionGasLimit": 12500000,
"testing": {
"stopOnFailedTest": true,
"stopOnFailedContractMatching": false,
"stopOnNoTests": true,
"testAllContracts": false,
"traceAll": false,
"assertionTesting": {
"enabled": true,
"testViewMethods": true,
"panicCodeConfig": {
"failOnCompilerInsertedPanic": false,
"failOnAssertion": true,
"failOnArithmeticUnderflow": false,
"failOnDivideByZero": false,
"failOnEnumTypeConversionOutOfBounds": false,
"failOnIncorrectStorageAccess": false,
"failOnPopEmptyArray": false,
"failOnOutOfBoundsArrayAccess": false,
"failOnAllocateTooMuchMemory": false,
"failOnCallUninitializedVariable": false
}
},
"propertyTesting": {
"enabled": false,
"testPrefixes": [
"property_"
]
},
"optimizationTesting": {
"enabled": false,
"testPrefixes": [
"optimize_"
]
},
"targetFunctionSignatures": [],
"excludeFunctionSignatures": []
},
"chainConfig": {
"codeSizeCheckDisabled": true,
"cheatCodes": {
"cheatCodesEnabled": true,
"enableFFI": false
},
"skipAccountChecks": true
}
},
"compilation": {
"platform": "crytic-compile",
"platformConfig": {
"target": ".",
"solcVersion": "",
"exportDirectory": "",
"args": ["--foundry-compile-all", "--foundry-out-directory", "artifacts"]
}
},
"logging": {
"level": "info",
"logDirectory": "",
"noColor": false
}
}
1 change: 1 addition & 0 deletions packages/contracts-bedrock/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"lint:fix": "yarn lint:contracts:fix && yarn lint:ts:fix",
"lint": "yarn lint:fix && yarn lint:check",
"typechain": "typechain --target ethers-v5 --out-dir dist/types --glob 'artifacts/!(build-info)/**/+([a-zA-Z0-9_]).json'",
"medusa": "FOUNDRY_PROFILE=medusa medusa fuzz",
"echidna:aliasing": "echidna-test --contract EchidnaFuzzAddressAliasing --config ./echidna.yaml .",
"echidna:burn:gas": "echidna-test --contract EchidnaFuzzBurnGas --config ./echidna.yaml .",
"echidna:burn:eth": "echidna-test --contract EchidnaFuzzBurnEth --config ./echidna.yaml .",
Expand Down

0 comments on commit 31f6095

Please sign in to comment.