diff --git a/.github/workflows/medusa.yml b/.github/workflows/medusa.yml index d6f166144c72b..f4676c7ba4873 100644 --- a/.github/workflows/medusa.yml +++ b/.github/workflows/medusa.yml @@ -14,6 +14,12 @@ jobs: with: submodules: recursive + - name: Setup Node.js 16.x + uses: actions/setup-node@master + with: + node-version: 16.x + cache: yarn + - name: Install dependencies working-directory: ./packages/contracts-bedrock run: yarn --frozen-lockfile --network-concurrency 1 diff --git a/packages/contracts-bedrock/contracts/L1/winddown/BalanceClaimer.sol b/packages/contracts-bedrock/contracts/L1/winddown/BalanceClaimer.sol index c19a31d99c82b..fcfe834500129 100644 --- a/packages/contracts-bedrock/contracts/L1/winddown/BalanceClaimer.sol +++ b/packages/contracts-bedrock/contracts/L1/winddown/BalanceClaimer.sol @@ -97,4 +97,4 @@ contract BalanceClaimer is Initializable, Semver, IBalanceClaimer { _canClaimTokens = MerkleProof.verify(_proof, root, _leaf); } -} \ No newline at end of file +} diff --git a/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/FuzzTest.t.sol b/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/FuzzTest.t.sol index 89503bff13fea..aab0358b9b77b 100644 --- a/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/FuzzTest.t.sol +++ b/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/FuzzTest.t.sol @@ -1,8 +1,11 @@ // 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'; +import "forge-std/console.sol"; + +import {BalanceClaimerGuidedHandlers} from "./handlers/guided/BalanceClaimer.t.sol"; +import {BalanceClaimerUnguidedHandlers} from "./handlers/unguided/BalanceClaimer.t.sol"; +import {BalanceClaimerProperties} from "./properties/BalanceClaimer.t.sol"; +import {IErc20BalanceWithdrawer} from "contracts/L1/interfaces/winddown/IErc20BalanceWithdrawer.sol"; contract FuzzTest is BalanceClaimerGuidedHandlers, BalanceClaimerUnguidedHandlers, BalanceClaimerProperties {} diff --git a/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/handlers/unguided/BalanceClaimer.t.sol b/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/handlers/unguided/BalanceClaimer.t.sol index 9aa23b6117a6a..32a93bc52e024 100644 --- a/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/handlers/unguided/BalanceClaimer.t.sol +++ b/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/handlers/unguided/BalanceClaimer.t.sol @@ -1,11 +1,68 @@ // SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.15; -import {BalanceClaimerSetup} from '../../setup/BalanceClaimer.t.sol'; +import "forge-std/console.sol"; + +import {BalanceClaimerSetup} from "../../setup/BalanceClaimer.t.sol"; +import {IErc20BalanceWithdrawer} from "contracts/L1/interfaces/winddown/IErc20BalanceWithdrawer.sol"; +import {IBalanceClaimer} from "contracts/L1/interfaces/winddown/IBalanceClaimer.sol"; contract BalanceClaimerUnguidedHandlers is BalanceClaimerSetup { - /// @custom:property-id - /// @custom:property - function handler_fooUnguided(address _caller, string memory _newGreeting) external { - } + function handler_initialize(address _ethBalanceWithdrawer, address _erc20BalanceWithdrawer, bytes32 _root) + external + { + try balanceClaimer.initialize(_ethBalanceWithdrawer, _erc20BalanceWithdrawer, _root) { + assert(false); // balanceClaimer should only be initialized once + } catch {} + } + + function handler_claim( + bytes32[] calldata _proof, + address _user, + uint256 _ethBalance, + IErc20BalanceWithdrawer.Erc20BalanceClaim[] calldata _erc20Claim, + address _caller + ) external { + vm.prank(_caller); + try balanceClaimer.claim(_proof, _user, _ethBalance, _erc20Claim) { + // TODO: check claim isnt in the valid set + assert(false); // random claim got accepted + } catch { + // TODO: assert claim is not in tree + // TODO: assert user already claimed + } + } + + function handler_canClaim( + bytes32[] calldata _proof, + address _user, + uint256 _ethBalance, + IErc20BalanceWithdrawer.Erc20BalanceClaim[] calldata _erc20Claim + ) external { + if (balanceClaimer.canClaim(_proof, _user, _ethBalance, _erc20Claim)) { + // TODO: check claim isnt in the valid set + assert(false); // random claim got accepted + } else { + // TODO: assert claim is not in tree + // TODO: assert user already claimed + } + } + + function handler_withdrawEthBalance(address _user, uint256 _ethClaim, address _caller) external { + try optimismPortal.withdrawEthBalance(_user, _ethClaim) { + assert(_caller == address(balanceClaimer)); + // TODO: update ghost variables + } catch {} + } + + function handler_withdrawErc20Balance( + address _user, + IErc20BalanceWithdrawer.Erc20BalanceClaim[] calldata _tokenClaims, + address _caller + ) external { + try l1StandardBridge.withdrawErc20Balance(_user, _tokenClaims) { + assert(_caller == address(balanceClaimer)); + // TODO: update ghost variables + } catch {} + } } diff --git a/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/setup/BalanceClaimer.t.sol b/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/setup/BalanceClaimer.t.sol index 9ed978aeebb13..0452df0852850 100644 --- a/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/setup/BalanceClaimer.t.sol +++ b/packages/contracts-bedrock/contracts/test/invariants/balance-claimer/setup/BalanceClaimer.t.sol @@ -20,22 +20,21 @@ contract BalanceClaimerSetup is CommonBase { 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)); + Proxy balanceClaimerProxy = new Proxy(address(this)); + + L1StandardBridge l1StandardBridgeImpl = new L1StandardBridge(payable(0), payable(address(balanceClaimerProxy))); + OptimismPortal optimismPortalImpl = new OptimismPortal({ + _l2Oracle: L2OutputOracle(address(0)), + _guardian: address(0), + _paused: false, + _config: SystemConfig(address(0)), + _balanceClaimer: address(balanceClaimerProxy) + }); // 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)); + new L1ChugSplashProxy(address(this)); + Proxy optimismPortalProxy = new Proxy(address(this)); - // Deploy BalanceClaimer implementation BalanceClaimer balanceClaimerImpl = new BalanceClaimer(); // Set BalanceClaimer implementation @@ -45,9 +44,11 @@ contract BalanceClaimerSetup is CommonBase { balanceClaimerImpl.initialize.selector, address(optimismPortalProxy), address(l1StandardBridgeProxy), - WinddownConstants.MERKLE_ROOT + bytes32(0) ) ); + optimismPortalProxy.upgradeTo(address(optimismPortalImpl)); + l1StandardBridgeProxy.setCode(address(l1StandardBridgeImpl).code); optimismPortal = OptimismPortal(payable(optimismPortalProxy)); l1StandardBridge = L1StandardBridge(payable(l1StandardBridgeProxy)); @@ -57,10 +58,10 @@ contract BalanceClaimerSetup is CommonBase { /// @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(address(balanceClaimer.ethBalanceWithdrawer()) == address(optimismPortal)); + assert(address(balanceClaimer.erc20BalanceWithdrawer()) == address(l1StandardBridge)); + assert(address(l1StandardBridge.BALANCE_CLAIMER()) == address(balanceClaimer)); assert(balanceClaimer.root() == bytes32(0)); } } diff --git a/packages/contracts-bedrock/foundry.toml b/packages/contracts-bedrock/foundry.toml index 3b04c12b8cd4c..c6c795fc2b3d6 100644 --- a/packages/contracts-bedrock/foundry.toml +++ b/packages/contracts-bedrock/foundry.toml @@ -25,7 +25,7 @@ fs_permissions = [ ] [profile.medusa] -src='contracts/test/invariants/balance-claimer' +src='contracts' test='contracts/test/invariants/balance-claimer' script='contracts/test/invariants/balance-claimer' diff --git a/packages/contracts-bedrock/medusa.json b/packages/contracts-bedrock/medusa.json index 412e674d4c997..ede7245d96192 100644 --- a/packages/contracts-bedrock/medusa.json +++ b/packages/contracts-bedrock/medusa.json @@ -6,7 +6,7 @@ "testLimit": 0, "shrinkLimit": 5000, "callSequenceLength": 100, - "corpusDirectory": "", + "corpusDirectory": "corpus", "coverageEnabled": true, "coverageFormats": [ "html", @@ -27,7 +27,7 @@ "blockGasLimit": 125000000, "transactionGasLimit": 12500000, "testing": { - "stopOnFailedTest": true, + "stopOnFailedTest": false, "stopOnFailedContractMatching": false, "stopOnNoTests": true, "testAllContracts": false,