Commit fa60a286 authored by Maurelian's avatar Maurelian Committed by GitHub

Introduce forked upgrade testing (#13323)

* feat: Basic upgrade test scaffolding

* Add Superchain Registry

* Fork from Registry

* feat: allowCheatcodes on setPreinstalls in L2Genesis

* feat: Refactory and clean up registry reads

* feat: cleanup Upgrade.s.sol

* fix: Move strings into function body

Upgrade has no constructor

* feat: Some cleanup

* feat: write optimismPortal2

* feat: Automatically run anvil on 8546

* feat: Add upgrade testing to Ci

* fix: use parameter to set UPGRADE_TEST env var

* feat: more cleanup

* fix: PR feedback

* tweak ci

* fix: justfile bug

* fix: Upgrade syntax errors

* add export MAINNET_RPC_URL to ci

* debug address in use

* feat: Allow cheatcodes for FFIInterface

* feat: use EIP1967Helper

* feat: improve comments in Setup.sol

* feat: add support for interop and optimized test setups

- Implemented the ability to use interop in test configurations.
- Added checks to skip tests when certain conditions for forked tests are met.
- Enhanced Setup with options for overriding L2 genesis and creating forks.
- Included additional logging for L1 setup processes.
- Enabled etching of deployed upgrade contracts for testing purposes.

* feat: Use ETH_RPC_URL as env var name

* test fixes for forking

* feat: anvil-fork-stop does not error

* feat: Do not mess with EVM env on a fork test

* feat: Take anvil out of the loop

* feat: Don't warp if forked

* fix: isForkTest not forkBlock

* lint

* feat: enforce forking from sepolia or mainnet

* fix(ctb): test fixes for a forked env

* Revert "feat: Take anvil out of the loop"

This reverts commit c70e8d7fd6f65319050b06df4eeb78461a682260.

* feat: remove anvil-fork-stop

also add helpful comments on just commands

* fix: unsilence anvil

* fix snapshot and semgrep

* temp: slightly faster just-upgrade loop

* feat: pin fork block

* feat: change upgrade_test to test_upgrade in config.yml for consistency

* feat: cache forked state

* speculative: skip l2 work

* feat: skip benchmark tests if isFork

* feat: skip deploying L2 tokens when forking

* feat: add skipIfForkTest

* feat: limit upgrade testing to L1 contracts

* feat: move skipping logic into Setup.sol

* feat: Simplify ci config for upgrade tests

* gas snapshot

* delete ignored deploy artifact

* remove unused added vm call

* feat: remove modifications to skipped test paths

* feat: improve block number handling

* feat: Document adding a new contract

* fix: ci config syntax error

* better justfile comments

* feat: skip some tests and log messages when you do

* feat: skip SystemConfig tests with incompatible iface

* feat: add returnIfForkTest and fix a bunch of tests

* feat: more test fixes and tweaks

* gas snapshot

* feat: Add test-upgrade-rerun to justfile and ci config

* feat: Make PINNED_BLOCK_NUMBER be not a magic number

* fix: long standing bug unrelated to this work

the L1 xDM test was exercising the L2 xDM. Fork testing caught this
because it skips deploying L2 contracts.
Deploying the L2 contracts to the same network as the L1 contracts was
always a bit janky anyways.

* feat: PDG: cleaner fork test handling

* feat: remove unused import

* fix incorrect vm.roll/warp skipping logic

* fix: OptimismPortal2 tests

* fix gas snapshot

* fix: restore test_list to contracts-bedrock-tests job

* feat(ci): Split up the test-upgrade CI job

* fix(ci): remove erroneous param reference

* feat: Improve caching of forked state

* feat: use config syntax for inserting rpc url

* debug: cache key

* feat: Fix cache key checksum

* Apply suggestions from code review
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>

* clarify comment about setup.setup forking

* feat: remove diff meant for upstack

* fix lint

* feat: make isForkTest private and add a getter

* debugging with annotations

* feat: fix test_findLatestGames_static_succeeds

* fix: OptimismPortal2 test_initialize_succeeds

Read guardian from chain rather than config

* feat: fix returnIfForkTest

Properly uses the return opcode to halt the test.

* fix: Portal tests for forking

* fix: DGF test for forking

* fix: Skip CGT tests on L1StandardBridge

* fix: Skip CGT tests on L1CrossDomainMessenger

* fix DGF testFuzz_create_succeeds

* fix: DGF testFuzz_create_sameUUID_reverts

* feat: remove debugging annotations

* fix: remove left over console

* fix: PermissionedDisputeGame tests

* fix: remove unused import

* fix: test_donateETH_succeeds for fork testing

* fix: isForkTest getter call

* feat: Temporarily skip UnexpectedRootClaim failures on forked upgrade tests

* Revert "feat: remove diff meant for upstack"

This reverts commit cab685617fd9db6961debe503f81042575b848f7.

* feat: clearer env var name for NO_MATCH_CONTRACTS

* fix gas snapshot

* fix test_constructor_succeeds tests after disableInit rebase

* lint

---------
Co-authored-by: default avatarMatt Solomon <matt@mattsolomon.dev>
parent ea5d8305
...@@ -698,6 +698,67 @@ jobs: ...@@ -698,6 +698,67 @@ jobs:
- "/root/.cache/go-build" - "/root/.cache/go-build"
- notify-failures-on-develop - notify-failures-on-develop
contracts-bedrock-tests-upgrade:
machine: true
resource_class: ethereum-optimism/latitude-1
steps:
- checkout
- attach_workspace: { at: "." }
- install-contracts-dependencies
- check-changed:
patterns: contracts-bedrock,op-node
- run:
name: Print dependencies
command: just dep-status
working_directory: packages/contracts-bedrock
- run:
name: Print forge version
command: forge --version
working_directory: packages/contracts-bedrock
- run:
name: Pull artifacts
command: bash scripts/ops/pull-artifacts.sh
working_directory: packages/contracts-bedrock
- run:
name: Write pinned block number for cache key
command: |
just print-pinned-block-number > ./pinnedBlockNumber.txt
cat pinnedBlockNumber.txt
pwd
working_directory: packages/contracts-bedrock
- restore_cache:
name: Restore forked state
key: forked-state-contracts-bedrock-tests-upgrade-{{ checksum "packages/contracts-bedrock/pinnedBlockNumber.txt" }}
- run:
name: Run tests
command: just test-upgrade
environment:
FOUNDRY_PROFILE: ci
ETH_RPC_URL: https://ci-mainnet-l1-archive.optimism.io
working_directory: packages/contracts-bedrock
no_output_timeout: 15m
- run:
name: Print failed test traces
command: just test-upgrade-rerun
environment:
FOUNDRY_PROFILE: ci
ETH_RPC_URL: https://ci-mainnet-l1-archive.optimism.io
working_directory: packages/contracts-bedrock
when: on_fail
- save_cache:
name: Save Go build cache
key: golang-build-cache-contracts-bedrock-tests-{{ checksum "go.sum" }}
paths:
- "/root/.cache/go-build"
- save_cache:
name: Save forked state
key: forked-state-contracts-bedrock-tests-upgrade-{{ checksum "packages/contracts-bedrock/pinnedBlockNumber.txt" }}
when: always
paths:
- "/root/.foundry/cache"
- notify-failures-on-develop
contracts-bedrock-checks: contracts-bedrock-checks:
machine: true machine: true
resource_class: ethereum-optimism/latitude-1 resource_class: ethereum-optimism/latitude-1
...@@ -1195,7 +1256,7 @@ workflows: ...@@ -1195,7 +1256,7 @@ workflows:
- contracts-bedrock-tests: - contracts-bedrock-tests:
# Test everything except PreimageOracle.t.sol since it's slow. # Test everything except PreimageOracle.t.sol since it's slow.
name: contracts-bedrock-tests name: contracts-bedrock-tests
test_list: find test -name "*.t.sol" -not -name "PreimageOracle.t.sol" test_list: find test -name "PreimageOracle.t.sol"
- contracts-bedrock-tests: - contracts-bedrock-tests:
# PreimageOracle test is slow, run it separately to unblock CI. # PreimageOracle test is slow, run it separately to unblock CI.
name: contracts-bedrock-tests-preimage-oracle name: contracts-bedrock-tests-preimage-oracle
...@@ -1214,6 +1275,8 @@ workflows: ...@@ -1214,6 +1275,8 @@ workflows:
test_flags: --report lcov test_flags: --report lcov
test_timeout: 1h test_timeout: 1h
test_profile: cicoverage test_profile: cicoverage
- contracts-bedrock-tests-upgrade:
name: contracts-bedrock-tests-upgrade
- contracts-bedrock-checks: - contracts-bedrock-checks:
requires: requires:
- contracts-bedrock-build - contracts-bedrock-build
......
...@@ -32,3 +32,6 @@ ...@@ -32,3 +32,6 @@
[submodule "packages/contracts-bedrock/lib/solady-v0.0.245"] [submodule "packages/contracts-bedrock/lib/solady-v0.0.245"]
path = packages/contracts-bedrock/lib/solady-v0.0.245 path = packages/contracts-bedrock/lib/solady-v0.0.245
url = https://github.com/vectorized/solady url = https://github.com/vectorized/solady
[submodule "packages/contracts-bedrock/lib/superchain-registry"]
path = packages/contracts-bedrock/lib/superchain-registry
url = https://github.com/ethereum-optimism/superchain-registry
...@@ -34,6 +34,7 @@ deployments/kontrol.json ...@@ -34,6 +34,7 @@ deployments/kontrol.json
deployments/kontrol.jsonReversed deployments/kontrol.jsonReversed
deployments/kontrol-fp.json deployments/kontrol-fp.json
deployments/kontrol-fp.jsonReversed deployments/kontrol-fp.jsonReversed
deployments/1-deploy.json
# Devnet config which changes with each 'make devnet-up' # Devnet config which changes with each 'make devnet-up'
deploy-config/devnetL1.json deploy-config/devnetL1.json
......
...@@ -45,6 +45,7 @@ fs_permissions = [ ...@@ -45,6 +45,7 @@ fs_permissions = [
{ access='read-write', path='./.testdata/' }, { access='read-write', path='./.testdata/' },
{ access='read', path='./kout-deployment' }, { access='read', path='./kout-deployment' },
{ access='read', path='./test/fixtures' }, { access='read', path='./test/fixtures' },
{ access='read', path='./lib/superchain-registry/superchain/configs/' },
] ]
# 5159 error code is selfdestruct error code # 5159 error code is selfdestruct error code
......
...@@ -56,6 +56,45 @@ test *ARGS: build-go-ffi ...@@ -56,6 +56,45 @@ test *ARGS: build-go-ffi
test-dev *ARGS: build-go-ffi test-dev *ARGS: build-go-ffi
FOUNDRY_PROFILE=lite forge test {{ARGS}} FOUNDRY_PROFILE=lite forge test {{ARGS}}
# Default block number for the forked upgrade path.
export pinnedBlockNumber := env_var_or_default('FORK_BLOCK_NUMBER', '21387830')
print-pinned-block-number:
echo $pinnedBlockNumber
# Runs upgrade path variant of contract tests.
# Env Vars:
# - ETH_RPC_URL must be set to a production (Sepolia or Mainnet) RPC URL.
# - FORK_BLOCK_NUMBER can be set in the env, or else will fallback to the default block number.
# Reusing the default block number greatly speeds up the test execution time by caching the
# rpc call responses in ~/.foundry/cache/rpc. The default block will need to be updated
# when the L1 chain is upgraded.
# TODO(opcm upgrades): unskip the "NMC" tests which fail on the forked upgrade path with "UnexpectedRootClaim" errors.
test-upgrade *ARGS: build-go-ffi
#!/bin/bash
echo "Running upgrade tests at block $pinnedBlockNumber"
export FORK_BLOCK_NUMBER=$pinnedBlockNumber
export NO_MATCH_CONTRACTS="OptimismPortal2WithMockERC20_Test|OptimismPortal2_FinalizeWithdrawal_Test|AnchorStateRegistry_Initialize_Test|AnchorStateRegistry_TryUpdateAnchorState_Test|FaultDisputeGame_Test|FaultDispute_1v1_Actors_Test"
FORK_RPC_URL=$ETH_RPC_URL \
UPGRADE_TEST=true \
forge test --match-path "test/{L1,dispute}/**" \
--no-match-contract "$NO_MATCH_CONTRACTS" \
{{ARGS}}
test-upgrade-rerun *ARGS: build-go-ffi
just test-upgrade {{ARGS}} --rerun -vvv
# Starts a local anvil node with a mainnet fork and sends it to the background
# Requires ETH_RPC_URL to be set to a production (Sepolia or Mainnet) RPC URL.
anvil-fork:
anvil --fork-url $ETH_RPC_URL
# Use anvil-fork in a separate terminal before running this command.
# Helpful for debugging.
test-upgrade-against-anvil *ARGS: build-go-ffi
FORK_RPC_URL=http://127.0.0.1:8545 \
UPGRADE_TEST=true \
forge test {{ARGS}}
# Runs standard contract tests with rerun flag. # Runs standard contract tests with rerun flag.
test-rerun: build-go-ffi test-rerun: build-go-ffi
forge test --rerun -vvv forge test --rerun -vvv
......
Subproject commit b9383cc1d0e97c6699e78dda06465aca182647c5
GasBenchMark_L1BlockInterop_DepositsComplete:test_depositsComplete_benchmark() (gas: 7567) GasBenchMark_L1BlockInterop_DepositsComplete:test_depositsComplete_benchmark() (gas: 7589)
GasBenchMark_L1BlockInterop_DepositsComplete_Warm:test_depositsComplete_benchmark() (gas: 5567) GasBenchMark_L1BlockInterop_DepositsComplete_Warm:test_depositsComplete_benchmark() (gas: 5589)
GasBenchMark_L1BlockInterop_SetValuesInterop:test_setL1BlockValuesInterop_benchmark() (gas: 175677) GasBenchMark_L1BlockInterop_SetValuesInterop:test_setL1BlockValuesInterop_benchmark() (gas: 175722)
GasBenchMark_L1BlockInterop_SetValuesInterop_Warm:test_setL1BlockValuesInterop_benchmark() (gas: 5099) GasBenchMark_L1BlockInterop_SetValuesInterop_Warm:test_setL1BlockValuesInterop_benchmark() (gas: 5144)
GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (gas: 158531) GasBenchMark_L1Block_SetValuesEcotone:test_setL1BlockValuesEcotone_benchmark() (gas: 158553)
GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7597) GasBenchMark_L1Block_SetValuesEcotone_Warm:test_setL1BlockValuesEcotone_benchmark() (gas: 7619)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 369280) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_0() (gas: 369235)
GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2967420) GasBenchMark_L1CrossDomainMessenger:test_sendMessage_benchmark_1() (gas: 2967442)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 564398) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_0() (gas: 564398)
GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4076613) GasBenchMark_L1StandardBridge_Deposit:test_depositERC20_benchmark_1() (gas: 4076568)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 467098) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_0() (gas: 467098)
GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3512802) GasBenchMark_L1StandardBridge_Deposit:test_depositETH_benchmark_1() (gas: 3512802)
GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 72664) GasBenchMark_L1StandardBridge_Finalize:test_finalizeETHWithdrawal_benchmark() (gas: 72619)
GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 92973) GasBenchMark_L2OutputOracle:test_proposeL2Output_benchmark() (gas: 92973)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68422) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark() (gas: 68422)
GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 69031) GasBenchMark_OptimismPortal:test_depositTransaction_benchmark_1() (gas: 69008)
GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155610) GasBenchMark_OptimismPortal:test_proveWithdrawalTransaction_benchmark() (gas: 155565)
\ No newline at end of file \ No newline at end of file
...@@ -33,6 +33,9 @@ contract L1CrossDomainMessenger_Test is CommonTest { ...@@ -33,6 +33,9 @@ contract L1CrossDomainMessenger_Test is CommonTest {
assertEq(address(impl.superchainConfig()), address(0)); assertEq(address(impl.superchainConfig()), address(0));
assertEq(address(impl.PORTAL()), address(0)); assertEq(address(impl.PORTAL()), address(0));
assertEq(address(impl.portal()), address(0)); assertEq(address(impl.portal()), address(0));
// The constructor now uses _disableInitializers, whereas OP Mainnet has the other messenger in storage
returnIfForkTest("L1CrossDomainMessenger_Test: impl storage differs on forked network");
assertEq(address(impl.OTHER_MESSENGER()), address(0)); assertEq(address(impl.OTHER_MESSENGER()), address(0));
assertEq(address(impl.otherMessenger()), address(0)); assertEq(address(impl.otherMessenger()), address(0));
} }
...@@ -129,7 +132,7 @@ contract L1CrossDomainMessenger_Test is CommonTest { ...@@ -129,7 +132,7 @@ contract L1CrossDomainMessenger_Test is CommonTest {
// Try to relay a v2 message. // Try to relay a v2 message.
vm.prank(address(optimismPortal)); vm.prank(address(optimismPortal));
l2CrossDomainMessenger.relayMessage( l1CrossDomainMessenger.relayMessage(
Encoding.encodeVersionedNonce({ _nonce: 0, _version: 2 }), // nonce Encoding.encodeVersionedNonce({ _nonce: 0, _version: 2 }), // nonce
sender, sender,
target, target,
...@@ -745,6 +748,9 @@ contract L1CrossDomainMessenger_Test is CommonTest { ...@@ -745,6 +748,9 @@ contract L1CrossDomainMessenger_Test is CommonTest {
/// @dev Tests that the sendMessage reverts when call value is non-zero with custom gas token. /// @dev Tests that the sendMessage reverts when call value is non-zero with custom gas token.
function test_sendMessage_customGasTokenWithValue_reverts() external { function test_sendMessage_customGasTokenWithValue_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("L1CrossDomainMessenger_Test: gas paying token functionality DNE on op mainnet");
// Mock the gasPayingToken function to return a custom gas token // Mock the gasPayingToken function to return a custom gas token
vm.mockCall( vm.mockCall(
address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))
...@@ -756,6 +762,9 @@ contract L1CrossDomainMessenger_Test is CommonTest { ...@@ -756,6 +762,9 @@ contract L1CrossDomainMessenger_Test is CommonTest {
/// @dev Tests that the relayMessage succeeds with a custom gas token when the call value is zero. /// @dev Tests that the relayMessage succeeds with a custom gas token when the call value is zero.
function test_relayMessage_customGasTokenAndNoValue_succeeds() external { function test_relayMessage_customGasTokenAndNoValue_succeeds() external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("L1CrossDomainMessenger_Test: gas paying token functionality DNE on op mainnet");
// Mock the gasPayingToken function to return a custom gas token // Mock the gasPayingToken function to return a custom gas token
vm.mockCall( vm.mockCall(
address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))
......
...@@ -72,9 +72,12 @@ contract L1ERC721Bridge_Test is CommonTest { ...@@ -72,9 +72,12 @@ contract L1ERC721Bridge_Test is CommonTest {
IL1ERC721Bridge impl = IL1ERC721Bridge(deploy.mustGetAddress("L1ERC721Bridge")); IL1ERC721Bridge impl = IL1ERC721Bridge(deploy.mustGetAddress("L1ERC721Bridge"));
assertEq(address(impl.MESSENGER()), address(0)); assertEq(address(impl.MESSENGER()), address(0));
assertEq(address(impl.messenger()), address(0)); assertEq(address(impl.messenger()), address(0));
assertEq(address(impl.superchainConfig()), address(0));
// The constructor now uses _disableInitializers, whereas OP Mainnet has the other bridge in storage
returnIfForkTest("L1ERC721Bridge_Test: impl storage differs on forked network");
assertEq(address(impl.OTHER_BRIDGE()), address(0)); assertEq(address(impl.OTHER_BRIDGE()), address(0));
assertEq(address(impl.otherBridge()), address(0)); assertEq(address(impl.otherBridge()), address(0));
assertEq(address(impl.superchainConfig()), address(0));
} }
/// @dev Tests that the proxy is initialized with the correct values. /// @dev Tests that the proxy is initialized with the correct values.
......
...@@ -27,6 +27,8 @@ contract L1StandardBridge_Getter_Test is CommonTest { ...@@ -27,6 +27,8 @@ contract L1StandardBridge_Getter_Test is CommonTest {
assert(address(l1StandardBridge.messenger()) == address(l1CrossDomainMessenger)); assert(address(l1StandardBridge.messenger()) == address(l1CrossDomainMessenger));
assert(address(l1StandardBridge.MESSENGER()) == address(l1CrossDomainMessenger)); assert(address(l1StandardBridge.MESSENGER()) == address(l1CrossDomainMessenger));
assert(l1StandardBridge.superchainConfig() == superchainConfig); assert(l1StandardBridge.superchainConfig() == superchainConfig);
returnIfForkTest("L1StandardBridge_Getter_Test: systemConfig() getter DNE on op mainnet");
assert(l1StandardBridge.systemConfig() == systemConfig); assert(l1StandardBridge.systemConfig() == systemConfig);
} }
} }
...@@ -38,6 +40,9 @@ contract L1StandardBridge_Initialize_Test is CommonTest { ...@@ -38,6 +40,9 @@ contract L1StandardBridge_Initialize_Test is CommonTest {
function test_constructor_succeeds() external virtual { function test_constructor_succeeds() external virtual {
IL1StandardBridge impl = IL1StandardBridge(deploy.mustGetAddress("L1StandardBridge")); IL1StandardBridge impl = IL1StandardBridge(deploy.mustGetAddress("L1StandardBridge"));
assertEq(address(impl.superchainConfig()), address(0)); assertEq(address(impl.superchainConfig()), address(0));
// The constructor now uses _disableInitializers, whereas OP Mainnet has these values in storage
returnIfForkTest("L1StandardBridge_Initialize_Test: impl storage differs on forked network");
assertEq(address(impl.MESSENGER()), address(0)); assertEq(address(impl.MESSENGER()), address(0));
assertEq(address(impl.messenger()), address(0)); assertEq(address(impl.messenger()), address(0));
assertEq(address(impl.OTHER_BRIDGE()), address(0)); assertEq(address(impl.OTHER_BRIDGE()), address(0));
...@@ -54,6 +59,8 @@ contract L1StandardBridge_Initialize_Test is CommonTest { ...@@ -54,6 +59,8 @@ contract L1StandardBridge_Initialize_Test is CommonTest {
assertEq(address(l1StandardBridge.OTHER_BRIDGE()), Predeploys.L2_STANDARD_BRIDGE); assertEq(address(l1StandardBridge.OTHER_BRIDGE()), Predeploys.L2_STANDARD_BRIDGE);
assertEq(address(l1StandardBridge.otherBridge()), Predeploys.L2_STANDARD_BRIDGE); assertEq(address(l1StandardBridge.otherBridge()), Predeploys.L2_STANDARD_BRIDGE);
assertEq(address(l2StandardBridge), Predeploys.L2_STANDARD_BRIDGE); assertEq(address(l2StandardBridge), Predeploys.L2_STANDARD_BRIDGE);
returnIfForkTest("L1StandardBridge_Initialize_Test: systemConfig() getter DNE on op mainnet");
assertEq(address(l1StandardBridge.systemConfig()), address(systemConfig)); assertEq(address(l1StandardBridge.systemConfig()), address(systemConfig));
} }
} }
...@@ -162,7 +169,7 @@ contract L1StandardBridge_Initialize_TestFail is CommonTest { } ...@@ -162,7 +169,7 @@ contract L1StandardBridge_Initialize_TestFail is CommonTest { }
contract L1StandardBridge_Receive_Test is CommonTest { contract L1StandardBridge_Receive_Test is CommonTest {
/// @dev Tests receive bridges ETH successfully. /// @dev Tests receive bridges ETH successfully.
function test_receive_succeeds() external { function test_receive_succeeds() external {
assertEq(address(optimismPortal).balance, 0); uint256 balanceBefore = address(optimismPortal).balance;
// The legacy event must be emitted for backwards compatibility // The legacy event must be emitted for backwards compatibility
vm.expectEmit(address(l1StandardBridge)); vm.expectEmit(address(l1StandardBridge));
...@@ -186,13 +193,16 @@ contract L1StandardBridge_Receive_Test is CommonTest { ...@@ -186,13 +193,16 @@ contract L1StandardBridge_Receive_Test is CommonTest {
vm.prank(alice, alice); vm.prank(alice, alice);
(bool success,) = address(l1StandardBridge).call{ value: 100 }(hex""); (bool success,) = address(l1StandardBridge).call{ value: 100 }(hex"");
assertEq(success, true); assertEq(success, true);
assertEq(address(optimismPortal).balance, 100); assertEq(address(optimismPortal).balance, balanceBefore + 100);
} }
} }
contract L1StandardBridge_Receive_TestFail is CommonTest { contract L1StandardBridge_Receive_TestFail is CommonTest {
/// @dev Tests receive function reverts with custom gas token. /// @dev Tests receive function reverts with custom gas token.
function testFuzz_receive_customGasToken_reverts(uint256 _value) external { function testFuzz_receive_customGasToken_reverts(uint256 _value) external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("L1StandardBridge_Receive_TestFail: gas paying token functionality DNE on op mainnet");
vm.prank(alice, alice); vm.prank(alice, alice);
vm.mockCall( vm.mockCall(
address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18)) address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(18))
...@@ -211,7 +221,9 @@ contract PreBridgeETH is CommonTest { ...@@ -211,7 +221,9 @@ contract PreBridgeETH is CommonTest {
/// @dev Asserts the expected calls and events for bridging ETH depending /// @dev Asserts the expected calls and events for bridging ETH depending
/// on whether the bridge call is legacy or not. /// on whether the bridge call is legacy or not.
function _preBridgeETH(bool isLegacy, uint256 value) internal { function _preBridgeETH(bool isLegacy, uint256 value) internal {
assertEq(address(optimismPortal).balance, 0); if (!isForkTest()) {
assertEq(address(optimismPortal).balance, 0);
}
uint256 nonce = l1CrossDomainMessenger.messageNonce(); uint256 nonce = l1CrossDomainMessenger.messageNonce();
uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION
address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger));
...@@ -280,8 +292,9 @@ contract L1StandardBridge_DepositETH_Test is PreBridgeETH { ...@@ -280,8 +292,9 @@ contract L1StandardBridge_DepositETH_Test is PreBridgeETH {
/// ETH ends up in the optimismPortal. /// ETH ends up in the optimismPortal.
function test_depositETH_succeeds() external { function test_depositETH_succeeds() external {
_preBridgeETH({ isLegacy: true, value: 500 }); _preBridgeETH({ isLegacy: true, value: 500 });
uint256 balanceBefore = address(optimismPortal).balance;
l1StandardBridge.depositETH{ value: 500 }(50000, hex"dead"); l1StandardBridge.depositETH{ value: 500 }(50000, hex"dead");
assertEq(address(optimismPortal).balance, 500); assertEq(address(optimismPortal).balance, balanceBefore + 500);
} }
} }
...@@ -296,6 +309,9 @@ contract L1StandardBridge_DepositETH_TestFail is CommonTest { ...@@ -296,6 +309,9 @@ contract L1StandardBridge_DepositETH_TestFail is CommonTest {
/// @dev Tests that depositing reverts with custom gas token. /// @dev Tests that depositing reverts with custom gas token.
function test_depositETH_customGasToken_reverts() external { function test_depositETH_customGasToken_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("L1StandardBridge_DepositETH_TestFail: gas paying token functionality DNE on op mainnet");
vm.mockCall( vm.mockCall(
address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))
); );
...@@ -313,14 +329,18 @@ contract L1StandardBridge_BridgeETH_Test is PreBridgeETH { ...@@ -313,14 +329,18 @@ contract L1StandardBridge_BridgeETH_Test is PreBridgeETH {
/// ETH ends up in the optimismPortal. /// ETH ends up in the optimismPortal.
function test_bridgeETH_succeeds() external { function test_bridgeETH_succeeds() external {
_preBridgeETH({ isLegacy: false, value: 500 }); _preBridgeETH({ isLegacy: false, value: 500 });
uint256 balanceBefore = address(optimismPortal).balance;
l1StandardBridge.bridgeETH{ value: 500 }(50000, hex"dead"); l1StandardBridge.bridgeETH{ value: 500 }(50000, hex"dead");
assertEq(address(optimismPortal).balance, 500); assertEq(address(optimismPortal).balance, balanceBefore + 500);
} }
} }
contract L1StandardBridge_BridgeETH_TestFail is PreBridgeETH { contract L1StandardBridge_BridgeETH_TestFail is PreBridgeETH {
/// @dev Tests that bridging eth reverts with custom gas token. /// @dev Tests that bridging eth reverts with custom gas token.
function test_bridgeETH_customGasToken_reverts() external { function test_bridgeETH_customGasToken_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("L1StandardBridge_BridgeETH_TestFail: gas paying token functionality DNE on op mainnet");
vm.prank(alice, alice); vm.prank(alice, alice);
vm.mockCall( vm.mockCall(
address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))
...@@ -335,7 +355,6 @@ contract PreBridgeETHTo is CommonTest { ...@@ -335,7 +355,6 @@ contract PreBridgeETHTo is CommonTest {
/// @dev Asserts the expected calls and events for bridging ETH to a different /// @dev Asserts the expected calls and events for bridging ETH to a different
/// address depending on whether the bridge call is legacy or not. /// address depending on whether the bridge call is legacy or not.
function _preBridgeETHTo(bool isLegacy, uint256 value) internal { function _preBridgeETHTo(bool isLegacy, uint256 value) internal {
assertEq(address(optimismPortal).balance, 0);
uint256 nonce = l1CrossDomainMessenger.messageNonce(); uint256 nonce = l1CrossDomainMessenger.messageNonce();
uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION uint256 version = 0; // Internal constant in the OptimismPortal: DEPOSIT_VERSION
address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)); address l1MessengerAliased = AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger));
...@@ -406,8 +425,9 @@ contract L1StandardBridge_DepositETHTo_Test is PreBridgeETHTo { ...@@ -406,8 +425,9 @@ contract L1StandardBridge_DepositETHTo_Test is PreBridgeETHTo {
/// ETH ends up in the optimismPortal. /// ETH ends up in the optimismPortal.
function test_depositETHTo_succeeds() external { function test_depositETHTo_succeeds() external {
_preBridgeETHTo({ isLegacy: true, value: 600 }); _preBridgeETHTo({ isLegacy: true, value: 600 });
uint256 balanceBefore = address(optimismPortal).balance;
l1StandardBridge.depositETHTo{ value: 600 }(bob, 60000, hex"dead"); l1StandardBridge.depositETHTo{ value: 600 }(bob, 60000, hex"dead");
assertEq(address(optimismPortal).balance, 600); assertEq(address(optimismPortal).balance, balanceBefore + 600);
} }
} }
...@@ -421,6 +441,9 @@ contract L1StandardBridge_DepositETHTo_TestFail is CommonTest { ...@@ -421,6 +441,9 @@ contract L1StandardBridge_DepositETHTo_TestFail is CommonTest {
) )
external external
{ {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("L1StandardBridge_DepositETHTo_TestFail: gas paying token functionality DNE on op mainnet");
vm.mockCall( vm.mockCall(
address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))
); );
...@@ -439,8 +462,9 @@ contract L1StandardBridge_BridgeETHTo_Test is PreBridgeETHTo { ...@@ -439,8 +462,9 @@ contract L1StandardBridge_BridgeETHTo_Test is PreBridgeETHTo {
/// ETH ends up in the optimismPortal. /// ETH ends up in the optimismPortal.
function test_bridgeETHTo_succeeds() external { function test_bridgeETHTo_succeeds() external {
_preBridgeETHTo({ isLegacy: false, value: 600 }); _preBridgeETHTo({ isLegacy: false, value: 600 });
uint256 balanceBefore = address(optimismPortal).balance;
l1StandardBridge.bridgeETHTo{ value: 600 }(bob, 60000, hex"dead"); l1StandardBridge.bridgeETHTo{ value: 600 }(bob, 60000, hex"dead");
assertEq(address(optimismPortal).balance, 600); assertEq(address(optimismPortal).balance, balanceBefore + 600);
} }
} }
...@@ -453,6 +477,9 @@ contract L1StandardBridge_BridgeETHTo_TestFail is PreBridgeETHTo { ...@@ -453,6 +477,9 @@ contract L1StandardBridge_BridgeETHTo_TestFail is PreBridgeETHTo {
) )
external external
{ {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("L1StandardBridge_BridgeETHTo_TestFail: gas paying token functionality DNE on op mainnet");
vm.mockCall( vm.mockCall(
address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))
); );
...@@ -662,6 +689,11 @@ contract L1StandardBridge_FinalizeETHWithdrawal_TestFail is CommonTest { ...@@ -662,6 +689,11 @@ contract L1StandardBridge_FinalizeETHWithdrawal_TestFail is CommonTest {
) )
external external
{ {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest(
"L1StandardBridge_FinalizeETHWithdrawal_TestFail: gas paying token functionality DNE on op mainnet"
);
vm.mockCall( vm.mockCall(
address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2)) address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(1), uint8(2))
); );
...@@ -765,6 +797,9 @@ contract L1StandardBridge_FinalizeBridgeETH_Test is CommonTest { ...@@ -765,6 +797,9 @@ contract L1StandardBridge_FinalizeBridgeETH_Test is CommonTest {
contract L1StandardBridge_FinalizeBridgeETH_TestFail is CommonTest { contract L1StandardBridge_FinalizeBridgeETH_TestFail is CommonTest {
/// @dev Tests that finalizing bridged reverts with custom gas token. /// @dev Tests that finalizing bridged reverts with custom gas token.
function testFuzz_finalizeBridgeETH_customGasToken_reverts(uint256 _value, bytes calldata _extraData) external { function testFuzz_finalizeBridgeETH_customGasToken_reverts(uint256 _value, bytes calldata _extraData) external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("L1StandardBridge_FinalizeBridgeETH_TestFail: gas paying token functionality DNE on op mainnet");
vm.mockCall( vm.mockCall(
address(l1StandardBridge.messenger()), address(l1StandardBridge.messenger()),
abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()), abi.encodeCall(ICrossDomainMessenger.xDomainMessageSender, ()),
......
...@@ -532,6 +532,8 @@ contract OptimismPortal_Test is CommonTest { ...@@ -532,6 +532,8 @@ contract OptimismPortal_Test is CommonTest {
/// @dev Tests that `depositERC20Transaction` reverts when the gas paying token is ether. /// @dev Tests that `depositERC20Transaction` reverts when the gas paying token is ether.
function test_depositERC20Transaction_noCustomGasToken_reverts() external { function test_depositERC20Transaction_noCustomGasToken_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal_Test: gas paying token functionality DNE on op mainnet");
// Check that the gas paying token is set to ether // Check that the gas paying token is set to ether
(address token,) = systemConfig.gasPayingToken(); (address token,) = systemConfig.gasPayingToken();
assertEq(token, Constants.ETHER); assertEq(token, Constants.ETHER);
...@@ -541,6 +543,8 @@ contract OptimismPortal_Test is CommonTest { ...@@ -541,6 +543,8 @@ contract OptimismPortal_Test is CommonTest {
} }
function test_depositERC20Transaction_balanceOverflow_reverts() external { function test_depositERC20Transaction_balanceOverflow_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal_Test: custom gas token DNE on op mainnet");
vm.mockCall(address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(42), 18)); vm.mockCall(address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(42), 18));
// The balance slot // The balance slot
...@@ -1338,7 +1342,9 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest { ...@@ -1338,7 +1342,9 @@ contract OptimismPortal_FinalizeWithdrawal_Test is CommonTest {
contract OptimismPortalUpgradeable_Test is CommonTest { contract OptimismPortalUpgradeable_Test is CommonTest {
/// @dev Tests that the proxy is initialized correctly. /// @dev Tests that the proxy is initialized correctly.
function test_params_initValuesOnProxy_succeeds() external view { function test_params_initValuesOnProxy_succeeds() external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal_Test: resource config varies on mainnet");
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = optimismPortal.params(); (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = optimismPortal.params();
IResourceMetering.ResourceConfig memory rcfg = systemConfig.resourceConfig(); IResourceMetering.ResourceConfig memory rcfg = systemConfig.resourceConfig();
...@@ -1759,6 +1765,8 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T ...@@ -1759,6 +1765,8 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T
) )
external external
{ {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal_Test: gas paying token functionality DNE on op mainnet");
// Ensure that msg.sender == tx.origin // Ensure that msg.sender == tx.origin
vm.startPrank(address(this), address(this)); vm.startPrank(address(this), address(this));
...@@ -1782,6 +1790,8 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T ...@@ -1782,6 +1790,8 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T
) )
external external
{ {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal_Test: gas paying token functionality DNE on op mainnet");
// Ensure that msg.sender != tx.origin // Ensure that msg.sender != tx.origin
vm.startPrank(address(this), address(1)); vm.startPrank(address(this), address(1));
...@@ -1797,6 +1807,8 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T ...@@ -1797,6 +1807,8 @@ contract OptimismPortalWithMockERC20_Test is OptimismPortal_FinalizeWithdrawal_T
/// @dev Tests that `depositTransaction` fails when a custom gas token is used and msg.value is non-zero. /// @dev Tests that `depositTransaction` fails when a custom gas token is used and msg.value is non-zero.
function test_depositTransaction_customGasTokenWithValue_reverts() external { function test_depositTransaction_customGasTokenWithValue_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal_Test: gas paying token functionality DNE on op mainnet");
// Mock the gas paying token to be the ERC20 token // Mock the gas paying token to be the ERC20 token
vm.mockCall( vm.mockCall(
address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18) address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(token), 18)
......
...@@ -53,21 +53,31 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -53,21 +53,31 @@ contract OptimismPortal2_Test is CommonTest {
assertEq(address(opImpl.disputeGameFactory()), address(0)); assertEq(address(opImpl.disputeGameFactory()), address(0));
assertEq(address(opImpl.systemConfig()), address(0)); assertEq(address(opImpl.systemConfig()), address(0));
assertEq(address(opImpl.superchainConfig()), address(0)); assertEq(address(opImpl.superchainConfig()), address(0));
assertEq(opImpl.l2Sender(), address(0));
assertEq(opImpl.respectedGameType().raw(), deploy.cfg().respectedGameType()); assertEq(opImpl.respectedGameType().raw(), deploy.cfg().respectedGameType());
// TODO(opcm upgrades): remove skip once upgrade path is implemented
returnIfForkTest("OptimismPortal2_Test: l2Sender is nonzero on OP mainnet");
assertEq(opImpl.l2Sender(), address(0));
} }
/// @dev Tests that the initializer sets the correct values. /// @dev Tests that the initializer sets the correct values.
/// @notice Marked virtual to be overridden in /// @notice Marked virtual to be overridden in
/// test/kontrol/deployment/DeploymentSummary.t.sol /// test/kontrol/deployment/DeploymentSummary.t.sol
function test_initialize_succeeds() external virtual { function test_initialize_succeeds() external virtual {
address guardian = deploy.cfg().superchainConfigGuardian();
assertEq(address(optimismPortal2.disputeGameFactory()), address(disputeGameFactory)); assertEq(address(optimismPortal2.disputeGameFactory()), address(disputeGameFactory));
assertEq(address(optimismPortal2.systemConfig()), address(systemConfig));
assertEq(optimismPortal2.guardian(), guardian);
assertEq(address(optimismPortal2.superchainConfig()), address(superchainConfig)); assertEq(address(optimismPortal2.superchainConfig()), address(superchainConfig));
assertEq(optimismPortal2.l2Sender(), Constants.DEFAULT_L2_SENDER); assertEq(optimismPortal2.l2Sender(), Constants.DEFAULT_L2_SENDER);
assertEq(optimismPortal2.paused(), false); assertEq(optimismPortal2.paused(), false);
assertEq(address(optimismPortal2.systemConfig()), address(systemConfig));
returnIfForkTest(
"OptimismPortal2_Initialize_Test: Do not check guardian and respectedGameType on forked networks"
);
address guardian = superchainConfig.guardian();
// This check is not valid for forked tests, as the guardian is not the same as the one in hardhat.json
assertEq(guardian, deploy.cfg().superchainConfigGuardian());
// This check is not valid on forked tests as the respectedGameType varies between OP Chains.
assertEq(optimismPortal2.respectedGameType().raw(), deploy.cfg().respectedGameType()); assertEq(optimismPortal2.respectedGameType().raw(), deploy.cfg().respectedGameType());
} }
...@@ -134,6 +144,9 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -134,6 +144,9 @@ contract OptimismPortal2_Test is CommonTest {
/// @dev Tests that `receive` successdully deposits ETH. /// @dev Tests that `receive` successdully deposits ETH.
function testFuzz_receive_succeeds(uint256 _value) external { function testFuzz_receive_succeeds(uint256 _value) external {
uint256 balanceBefore = address(optimismPortal2).balance;
_value = bound(_value, 0, type(uint256).max - balanceBefore);
vm.expectEmit(address(optimismPortal2)); vm.expectEmit(address(optimismPortal2));
emitTransactionDeposited({ emitTransactionDeposited({
_from: alice, _from: alice,
...@@ -151,7 +164,7 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -151,7 +164,7 @@ contract OptimismPortal2_Test is CommonTest {
(bool s,) = address(optimismPortal2).call{ value: _value }(hex""); (bool s,) = address(optimismPortal2).call{ value: _value }(hex"");
assertTrue(s); assertTrue(s);
assertEq(address(optimismPortal2).balance, _value); assertEq(address(optimismPortal2).balance, balanceBefore + _value);
} }
/// @dev Tests that `depositTransaction` reverts when the destination address is non-zero /// @dev Tests that `depositTransaction` reverts when the destination address is non-zero
...@@ -230,6 +243,9 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -230,6 +243,9 @@ contract OptimismPortal2_Test is CommonTest {
); );
if (_isCreation) _to = address(0); if (_isCreation) _to = address(0);
uint256 balanceBefore = address(optimismPortal2).balance;
_mint = bound(_mint, 0, type(uint256).max - balanceBefore);
// EOA emulation // EOA emulation
vm.expectEmit(address(optimismPortal2)); vm.expectEmit(address(optimismPortal2));
emitTransactionDeposited({ emitTransactionDeposited({
...@@ -251,7 +267,7 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -251,7 +267,7 @@ contract OptimismPortal2_Test is CommonTest {
_isCreation: _isCreation, _isCreation: _isCreation,
_data: _data _data: _data
}); });
assertEq(address(optimismPortal2).balance, _mint); assertEq(address(optimismPortal2).balance, balanceBefore + _mint);
} }
/// @dev Tests that `depositTransaction` succeeds for a contract. /// @dev Tests that `depositTransaction` succeeds for a contract.
...@@ -274,6 +290,9 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -274,6 +290,9 @@ contract OptimismPortal2_Test is CommonTest {
); );
if (_isCreation) _to = address(0); if (_isCreation) _to = address(0);
uint256 balanceBefore = address(optimismPortal2).balance;
_mint = bound(_mint, 0, type(uint256).max - balanceBefore);
vm.expectEmit(address(optimismPortal2)); vm.expectEmit(address(optimismPortal2));
emitTransactionDeposited({ emitTransactionDeposited({
_from: AddressAliasHelper.applyL1ToL2Alias(address(this)), _from: AddressAliasHelper.applyL1ToL2Alias(address(this)),
...@@ -294,7 +313,7 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -294,7 +313,7 @@ contract OptimismPortal2_Test is CommonTest {
_isCreation: _isCreation, _isCreation: _isCreation,
_data: _data _data: _data
}); });
assertEq(address(optimismPortal2).balance, _mint); assertEq(address(optimismPortal2).balance, balanceBefore + _mint);
} }
/// @dev Tests that the gas paying token can be set. /// @dev Tests that the gas paying token can be set.
...@@ -306,6 +325,9 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -306,6 +325,9 @@ contract OptimismPortal2_Test is CommonTest {
) )
external external
{ {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal2_Test: gas paying token functionality DNE on op mainnet");
vm.expectEmit(address(optimismPortal2)); vm.expectEmit(address(optimismPortal2));
emit TransactionDeposited( emit TransactionDeposited(
0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001, 0xDeaDDEaDDeAdDeAdDEAdDEaddeAddEAdDEAd0001,
...@@ -334,6 +356,9 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -334,6 +356,9 @@ contract OptimismPortal2_Test is CommonTest {
) )
external external
{ {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal2_Test: gas paying token functionality DNE on op mainnet");
if (bytes(_name).length > 32) { if (bytes(_name).length > 32) {
_name = _name[0:32]; _name = _name[0:32];
} }
...@@ -346,6 +371,7 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -346,6 +371,7 @@ contract OptimismPortal2_Test is CommonTest {
vm.recordLogs(); vm.recordLogs();
vm.deal(address(systemConfig), 100 ether);
vm.prank(address(systemConfig)); vm.prank(address(systemConfig));
optimismPortal2.setGasPayingToken({ _token: _token, _decimals: 18, _name: name, _symbol: symbol }); optimismPortal2.setGasPayingToken({ _token: _token, _decimals: 18, _name: name, _symbol: symbol });
...@@ -375,6 +401,9 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -375,6 +401,9 @@ contract OptimismPortal2_Test is CommonTest {
/// @dev Tests that the gas paying token cannot be set by a non-system config. /// @dev Tests that the gas paying token cannot be set by a non-system config.
function test_setGasPayingToken_notSystemConfig_fails(address _caller) external { function test_setGasPayingToken_notSystemConfig_fails(address _caller) external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal2_Test: gas paying token functionality DNE on op mainnet");
vm.assume(_caller != address(systemConfig)); vm.assume(_caller != address(systemConfig));
vm.prank(_caller); vm.prank(_caller);
vm.expectRevert(Unauthorized.selector); vm.expectRevert(Unauthorized.selector);
...@@ -383,6 +412,9 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -383,6 +412,9 @@ contract OptimismPortal2_Test is CommonTest {
/// @dev Tests that `depositERC20Transaction` reverts when the gas paying token is ether. /// @dev Tests that `depositERC20Transaction` reverts when the gas paying token is ether.
function test_depositERC20Transaction_noCustomGasToken_reverts() external { function test_depositERC20Transaction_noCustomGasToken_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal2_Test: gas paying token functionality DNE on op mainnet");
// Check that the gas paying token is set to ether // Check that the gas paying token is set to ether
(address token,) = systemConfig.gasPayingToken(); (address token,) = systemConfig.gasPayingToken();
assertEq(token, Constants.ETHER); assertEq(token, Constants.ETHER);
...@@ -392,6 +424,8 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -392,6 +424,8 @@ contract OptimismPortal2_Test is CommonTest {
} }
function test_depositERC20Transaction_balanceOverflow_reverts() external { function test_depositERC20Transaction_balanceOverflow_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal2_Test: gas paying token functionality DNE on op mainnet");
vm.mockCall(address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(42), 18)); vm.mockCall(address(systemConfig), abi.encodeCall(systemConfig.gasPayingToken, ()), abi.encode(address(42), 18));
// The balance slot // The balance slot
...@@ -411,6 +445,8 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -411,6 +445,8 @@ contract OptimismPortal2_Test is CommonTest {
/// @dev Tests that `balance()` returns the correct balance when the gas paying token is ether. /// @dev Tests that `balance()` returns the correct balance when the gas paying token is ether.
function testFuzz_balance_ether_succeeds(uint256 _amount) external { function testFuzz_balance_ether_succeeds(uint256 _amount) external {
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal2_Test: gas paying token functionality DNE on op mainnet");
// Check that the gas paying token is set to ether // Check that the gas paying token is set to ether
(address token,) = systemConfig.gasPayingToken(); (address token,) = systemConfig.gasPayingToken();
assertEq(token, Constants.ETHER); assertEq(token, Constants.ETHER);
...@@ -428,6 +464,7 @@ contract OptimismPortal2_Test is CommonTest { ...@@ -428,6 +464,7 @@ contract OptimismPortal2_Test is CommonTest {
vm.deal(alice, _amount); vm.deal(alice, _amount);
uint256 preBalance = address(optimismPortal2).balance; uint256 preBalance = address(optimismPortal2).balance;
_amount = bound(_amount, 0, type(uint256).max - preBalance);
vm.startStateDiffRecording(); vm.startStateDiffRecording();
optimismPortal2.donateETH{ value: _amount }(); optimismPortal2.donateETH{ value: _amount }();
...@@ -506,10 +543,12 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest { ...@@ -506,10 +543,12 @@ contract OptimismPortal2_FinalizeWithdrawal_Test is CommonTest {
/// @dev Setup the system for a ready-to-use state. /// @dev Setup the system for a ready-to-use state.
function setUp() public virtual override { function setUp() public virtual override {
_proposedBlockNumber = 0xFF; _proposedBlockNumber = 0xFF;
GameType respectedGameType = optimismPortal2.respectedGameType();
uint256 bondAmount = disputeGameFactory.initBonds(respectedGameType);
game = IFaultDisputeGame( game = IFaultDisputeGame(
payable( payable(
address( address(
disputeGameFactory.create( disputeGameFactory.create{ value: bondAmount }(
optimismPortal2.respectedGameType(), Claim.wrap(_outputRoot), abi.encode(_proposedBlockNumber) optimismPortal2.respectedGameType(), Claim.wrap(_outputRoot), abi.encode(_proposedBlockNumber)
) )
) )
...@@ -1607,7 +1646,8 @@ contract OptimismPortal2_Upgradeable_Test is CommonTest { ...@@ -1607,7 +1646,8 @@ contract OptimismPortal2_Upgradeable_Test is CommonTest {
} }
/// @dev Tests that the proxy is initialized correctly. /// @dev Tests that the proxy is initialized correctly.
function test_params_initValuesOnProxy_succeeds() external view { function test_params_initValuesOnProxy_succeeds() external {
skipIfForkTest("OptimismPortal2_Test: resource config varies on mainnet");
(uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = optimismPortal2.params(); (uint128 prevBaseFee, uint64 prevBoughtGas, uint64 prevBlockNum) = optimismPortal2.params();
IResourceMetering.ResourceConfig memory rcfg = systemConfig.resourceConfig(); IResourceMetering.ResourceConfig memory rcfg = systemConfig.resourceConfig();
...@@ -1747,6 +1787,9 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal ...@@ -1747,6 +1787,9 @@ contract OptimismPortal2WithMockERC20_Test is OptimismPortal2_FinalizeWithdrawal
function setUp() public virtual override { function setUp() public virtual override {
super.setUp(); super.setUp();
token = new MockERC20("Test", "TST", 18); token = new MockERC20("Test", "TST", 18);
// TODO(opcm upgrades): remove skip once upgrade path is implemented
skipIfForkTest("OptimismPortal2_Test: gas paying token functionality DNE on op mainnet");
} }
function depositERC20Transaction( function depositERC20Transaction(
......
...@@ -24,7 +24,10 @@ contract ProtocolVersions_Init is CommonTest { ...@@ -24,7 +24,10 @@ contract ProtocolVersions_Init is CommonTest {
contract ProtocolVersions_Initialize_Test is ProtocolVersions_Init { contract ProtocolVersions_Initialize_Test is ProtocolVersions_Init {
/// @dev Tests that initialization sets the correct values. /// @dev Tests that initialization sets the correct values.
function test_initialize_values_succeeds() external view { function test_initialize_values_succeeds() external {
skipIfForkTest(
"ProtocolVersions_Initialize_Test: cannot test initialization on forked network against hardhat config"
);
IProtocolVersions protocolVersionsImpl = IProtocolVersions(deploy.mustGetAddress("ProtocolVersions")); IProtocolVersions protocolVersionsImpl = IProtocolVersions(deploy.mustGetAddress("ProtocolVersions"));
address owner = deploy.cfg().finalSystemOwner(); address owner = deploy.cfg().finalSystemOwner();
...@@ -40,7 +43,6 @@ contract ProtocolVersions_Initialize_Test is ProtocolVersions_Init { ...@@ -40,7 +43,6 @@ contract ProtocolVersions_Initialize_Test is ProtocolVersions_Init {
/// @dev Ensures that the events are emitted during initialization. /// @dev Ensures that the events are emitted during initialization.
function test_initialize_events_succeeds() external { function test_initialize_events_succeeds() external {
IProtocolVersions protocolVersionsImpl = IProtocolVersions(deploy.mustGetAddress("ProtocolVersions")); IProtocolVersions protocolVersionsImpl = IProtocolVersions(deploy.mustGetAddress("ProtocolVersions"));
assertEq(protocolVersionsImpl.owner(), address(0));
// Wipe out the initialized slot so the proxy can be initialized again // Wipe out the initialized slot so the proxy can be initialized again
vm.store(address(protocolVersions), bytes32(0), bytes32(0)); vm.store(address(protocolVersions), bytes32(0), bytes32(0));
......
...@@ -12,6 +12,11 @@ import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol"; ...@@ -12,6 +12,11 @@ import { ISuperchainConfig } from "interfaces/L1/ISuperchainConfig.sol";
import { DeployUtils } from "scripts/libraries/DeployUtils.sol"; import { DeployUtils } from "scripts/libraries/DeployUtils.sol";
contract SuperchainConfig_Init_Test is CommonTest { contract SuperchainConfig_Init_Test is CommonTest {
function setUp() public virtual override {
super.setUp();
skipIfForkTest("SuperchainConfig_Init_Test: cannot test initialization on forked network");
}
/// @dev Tests that initialization sets the correct values. These are defined in CommonTest.sol. /// @dev Tests that initialization sets the correct values. These are defined in CommonTest.sol.
function test_initialize_unpaused_succeeds() external view { function test_initialize_unpaused_succeeds() external view {
assertFalse(superchainConfig.paused()); assertFalse(superchainConfig.paused());
......
...@@ -34,6 +34,7 @@ contract SystemConfig_Initialize_Test is SystemConfig_Init { ...@@ -34,6 +34,7 @@ contract SystemConfig_Initialize_Test is SystemConfig_Init {
function setUp() public virtual override { function setUp() public virtual override {
super.setUp(); super.setUp();
skipIfForkTest("SystemConfig_Initialize_Test: cannot test initialization on forked network");
batchInbox = deploy.cfg().batchInboxAddress(); batchInbox = deploy.cfg().batchInboxAddress();
owner = deploy.cfg().finalSystemOwner(); owner = deploy.cfg().finalSystemOwner();
basefeeScalar = deploy.cfg().basefeeScalar(); basefeeScalar = deploy.cfg().basefeeScalar();
...@@ -290,10 +291,12 @@ contract SystemConfig_Init_ResourceConfig is SystemConfig_Init { ...@@ -290,10 +291,12 @@ contract SystemConfig_Init_ResourceConfig is SystemConfig_Init {
) )
internal internal
{ {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Init_ResourceConfig: initialize() interface differs from mainnet.");
// Wipe out the initialized slot so the proxy can be initialized again // Wipe out the initialized slot so the proxy can be initialized again
vm.store(address(systemConfig), bytes32(0), bytes32(0)); vm.store(address(systemConfig), bytes32(0), bytes32(0));
// Fetch the current gas limit // Fetch the current gas limit
uint64 gasLimit = uint64(deploy.cfg().l2GenesisBlockGasLimit()); uint64 gasLimit = systemConfig.gasLimit();
vm.expectRevert(bytes(revertMessage)); vm.expectRevert(bytes(revertMessage));
systemConfig.initialize({ systemConfig.initialize({
...@@ -511,12 +514,16 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { ...@@ -511,12 +514,16 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
/// @notice Ensures that `setGasConfig` reverts if version byte is set. /// @notice Ensures that `setGasConfig` reverts if version byte is set.
function test_setGasConfig_badValues_reverts() external { function test_setGasConfig_badValues_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'scalar exceeds max' check DNE on op mainnet");
vm.prank(systemConfig.owner()); vm.prank(systemConfig.owner());
vm.expectRevert("SystemConfig: scalar exceeds max."); vm.expectRevert("SystemConfig: scalar exceeds max.");
systemConfig.setGasConfig({ _overhead: 0, _scalar: type(uint256).max }); systemConfig.setGasConfig({ _overhead: 0, _scalar: type(uint256).max });
} }
function test_setGasConfigEcotone_notOwner_reverts() external { function test_setGasConfigEcotone_notOwner_reverts() external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setGasConfigEcotone' method DNE on op mainnet");
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
systemConfig.setGasConfigEcotone({ _basefeeScalar: 0, _blobbasefeeScalar: 0 }); systemConfig.setGasConfigEcotone({ _basefeeScalar: 0, _blobbasefeeScalar: 0 });
} }
...@@ -551,12 +558,16 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { ...@@ -551,12 +558,16 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
/// @dev Tests that `setEIP1559Params` reverts if the caller is not the owner. /// @dev Tests that `setEIP1559Params` reverts if the caller is not the owner.
function test_setEIP1559Params_notOwner_reverts(uint32 _denominator, uint32 _elasticity) external { function test_setEIP1559Params_notOwner_reverts(uint32 _denominator, uint32 _elasticity) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
vm.expectRevert("Ownable: caller is not the owner"); vm.expectRevert("Ownable: caller is not the owner");
systemConfig.setEIP1559Params({ _denominator: _denominator, _elasticity: _elasticity }); systemConfig.setEIP1559Params({ _denominator: _denominator, _elasticity: _elasticity });
} }
/// @dev Tests that `setEIP1559Params` reverts if the denominator is zero. /// @dev Tests that `setEIP1559Params` reverts if the denominator is zero.
function test_setEIP1559Params_zeroDenominator_reverts(uint32 _elasticity) external { function test_setEIP1559Params_zeroDenominator_reverts(uint32 _elasticity) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
vm.prank(systemConfig.owner()); vm.prank(systemConfig.owner());
vm.expectRevert("SystemConfig: denominator must be >= 1"); vm.expectRevert("SystemConfig: denominator must be >= 1");
systemConfig.setEIP1559Params({ _denominator: 0, _elasticity: _elasticity }); systemConfig.setEIP1559Params({ _denominator: 0, _elasticity: _elasticity });
...@@ -564,6 +575,8 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init { ...@@ -564,6 +575,8 @@ contract SystemConfig_Setters_TestFail is SystemConfig_Init {
/// @dev Tests that `setEIP1559Params` reverts if the elasticity is zero. /// @dev Tests that `setEIP1559Params` reverts if the elasticity is zero.
function test_setEIP1559Params_zeroElasticity_reverts(uint32 _denominator) external { function test_setEIP1559Params_zeroElasticity_reverts(uint32 _denominator) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
_denominator = uint32(bound(_denominator, 1, type(uint32).max)); _denominator = uint32(bound(_denominator, 1, type(uint32).max));
vm.prank(systemConfig.owner()); vm.prank(systemConfig.owner());
vm.expectRevert("SystemConfig: elasticity must be >= 1"); vm.expectRevert("SystemConfig: elasticity must be >= 1");
...@@ -596,6 +609,8 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -596,6 +609,8 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
} }
function testFuzz_setGasConfigEcotone_succeeds(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external { function testFuzz_setGasConfigEcotone_succeeds(uint32 _basefeeScalar, uint32 _blobbasefeeScalar) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setGasConfigEcotone' method DNE on op mainnet");
bytes32 encoded = bytes32 encoded =
ffi.encodeScalarEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar }); ffi.encodeScalarEcotone({ _basefeeScalar: _basefeeScalar, _blobbasefeeScalar: _blobbasefeeScalar });
...@@ -639,6 +654,8 @@ contract SystemConfig_Setters_Test is SystemConfig_Init { ...@@ -639,6 +654,8 @@ contract SystemConfig_Setters_Test is SystemConfig_Init {
/// @dev Tests that `setEIP1559Params` updates the EIP1559 parameters successfully. /// @dev Tests that `setEIP1559Params` updates the EIP1559 parameters successfully.
function testFuzz_setEIP1559Params_succeeds(uint32 _denominator, uint32 _elasticity) external { function testFuzz_setEIP1559Params_succeeds(uint32 _denominator, uint32 _elasticity) external {
// TODO(opcm upgrades): remove skip once upgrade is implemented
skipIfForkTest("SystemConfig_Setters_TestFail: 'setEIP1559Params' method DNE on op mainnet");
_denominator = uint32(bound(_denominator, 2, type(uint32).max)); _denominator = uint32(bound(_denominator, 2, type(uint32).max));
_elasticity = uint32(bound(_elasticity, 2, type(uint32).max)); _elasticity = uint32(bound(_elasticity, 2, type(uint32).max));
......
...@@ -54,6 +54,8 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init { ...@@ -54,6 +54,8 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init {
vm.deal(address(this), _value); vm.deal(address(this), _value);
uint256 gameCountBefore = disputeGameFactory.gameCount();
vm.expectEmit(false, true, true, false); vm.expectEmit(false, true, true, false);
emit DisputeGameCreated(address(0), gt, rootClaim); emit DisputeGameCreated(address(0), gt, rootClaim);
IDisputeGame proxy = disputeGameFactory.create{ value: _value }(gt, rootClaim, extraData); IDisputeGame proxy = disputeGameFactory.create{ value: _value }(gt, rootClaim, extraData);
...@@ -63,9 +65,9 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init { ...@@ -63,9 +65,9 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init {
// Ensure that the dispute game was assigned to the `disputeGames` mapping. // Ensure that the dispute game was assigned to the `disputeGames` mapping.
assertEq(address(game), address(proxy)); assertEq(address(game), address(proxy));
assertEq(Timestamp.unwrap(timestamp), block.timestamp); assertEq(Timestamp.unwrap(timestamp), block.timestamp);
assertEq(disputeGameFactory.gameCount(), 1); assertEq(disputeGameFactory.gameCount(), gameCountBefore + 1);
(, Timestamp timestamp2, IDisputeGame game2) = disputeGameFactory.gameAtIndex(0); (, Timestamp timestamp2, IDisputeGame game2) = disputeGameFactory.gameAtIndex(gameCountBefore);
assertEq(address(game2), address(proxy)); assertEq(address(game2), address(proxy));
assertEq(Timestamp.unwrap(timestamp2), block.timestamp); assertEq(Timestamp.unwrap(timestamp2), block.timestamp);
...@@ -122,10 +124,12 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init { ...@@ -122,10 +124,12 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init {
disputeGameFactory.setImplementation(GameType.wrap(i), IDisputeGame(address(fakeClone))); disputeGameFactory.setImplementation(GameType.wrap(i), IDisputeGame(address(fakeClone)));
} }
uint256 bondAmount = disputeGameFactory.initBonds(gt);
// Create our first dispute game - this should succeed. // Create our first dispute game - this should succeed.
vm.expectEmit(false, true, true, false); vm.expectEmit(false, true, true, false);
emit DisputeGameCreated(address(0), gt, rootClaim); emit DisputeGameCreated(address(0), gt, rootClaim);
IDisputeGame proxy = disputeGameFactory.create(gt, rootClaim, extraData); IDisputeGame proxy = disputeGameFactory.create{ value: bondAmount }(gt, rootClaim, extraData);
(IDisputeGame game, Timestamp timestamp) = disputeGameFactory.games(gt, rootClaim, extraData); (IDisputeGame game, Timestamp timestamp) = disputeGameFactory.games(gt, rootClaim, extraData);
// Ensure that the dispute game was assigned to the `disputeGames` mapping. // Ensure that the dispute game was assigned to the `disputeGames` mapping.
...@@ -136,7 +140,7 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init { ...@@ -136,7 +140,7 @@ contract DisputeGameFactory_Create_Test is DisputeGameFactory_Init {
vm.expectRevert( vm.expectRevert(
abi.encodeWithSelector(GameAlreadyExists.selector, disputeGameFactory.getGameUUID(gt, rootClaim, extraData)) abi.encodeWithSelector(GameAlreadyExists.selector, disputeGameFactory.getGameUUID(gt, rootClaim, extraData))
); );
disputeGameFactory.create(gt, rootClaim, extraData); disputeGameFactory.create{ value: bondAmount }(gt, rootClaim, extraData);
} }
function changeClaimStatus(Claim _claim, VMStatus _status) public pure returns (Claim out_) { function changeClaimStatus(Claim _claim, VMStatus _status) public pure returns (Claim out_) {
...@@ -172,7 +176,9 @@ contract DisputeGameFactory_SetInitBond_Test is DisputeGameFactory_Init { ...@@ -172,7 +176,9 @@ contract DisputeGameFactory_SetInitBond_Test is DisputeGameFactory_Init {
/// @dev Tests that the `setInitBond` function properly sets the init bond for a given `GameType`. /// @dev Tests that the `setInitBond` function properly sets the init bond for a given `GameType`.
function test_setInitBond_succeeds() public { function test_setInitBond_succeeds() public {
// There should be no init bond for the `GameTypes.CANNON` enum value, it has not been set. // There should be no init bond for the `GameTypes.CANNON` enum value, it has not been set.
assertEq(disputeGameFactory.initBonds(GameTypes.CANNON), 0); if (!isForkTest()) {
assertEq(disputeGameFactory.initBonds(GameTypes.CANNON), 0);
}
vm.expectEmit(true, true, true, true, address(disputeGameFactory)); vm.expectEmit(true, true, true, true, address(disputeGameFactory));
emit InitBondUpdated(GameTypes.CANNON, 1 ether); emit InitBondUpdated(GameTypes.CANNON, 1 ether);
...@@ -261,7 +267,8 @@ contract DisputeGameFactory_FindLatestGames_Test is DisputeGameFactory_Init { ...@@ -261,7 +267,8 @@ contract DisputeGameFactory_FindLatestGames_Test is DisputeGameFactory_Init {
/// @dev Tests that `findLatestGames` returns the correct games. /// @dev Tests that `findLatestGames` returns the correct games.
function test_findLatestGames_static_succeeds() public { function test_findLatestGames_static_succeeds() public {
// Create some dispute games of varying game types. // Create some dispute games of varying game types, repeatedly iterating over the game types 0, 1, 2.
// 1 << 5 = 32, resulting in the final three games added being ordered 2, 0, 1.
for (uint256 i; i < 1 << 5; i++) { for (uint256 i; i < 1 << 5; i++) {
disputeGameFactory.create(GameType.wrap(uint8(i % 3)), Claim.wrap(bytes32(i)), abi.encode(i)); disputeGameFactory.create(GameType.wrap(uint8(i % 3)), Claim.wrap(bytes32(i)), abi.encode(i));
} }
...@@ -270,23 +277,31 @@ contract DisputeGameFactory_FindLatestGames_Test is DisputeGameFactory_Init { ...@@ -270,23 +277,31 @@ contract DisputeGameFactory_FindLatestGames_Test is DisputeGameFactory_Init {
IDisputeGameFactory.GameSearchResult[] memory games; IDisputeGameFactory.GameSearchResult[] memory games;
games = disputeGameFactory.findLatestGames(GameType.wrap(0), gameCount - 1, 1); uint256 start = gameCount - 1;
// Find type 1 games.
games = disputeGameFactory.findLatestGames(GameType.wrap(1), start, 1);
assertEq(games.length, 1); assertEq(games.length, 1);
assertEq(games[0].index, 30); // The type 1 game should be the last one added.
assertEq(games[0].index, start);
(GameType gameType, Timestamp createdAt, address game) = games[0].metadata.unpack(); (GameType gameType, Timestamp createdAt, address game) = games[0].metadata.unpack();
assertEq(gameType.raw(), 0); assertEq(gameType.raw(), 1);
assertEq(createdAt.raw(), block.timestamp); assertEq(createdAt.raw(), block.timestamp);
games = disputeGameFactory.findLatestGames(GameType.wrap(1), gameCount - 1, 1); // Find type 0 games.
games = disputeGameFactory.findLatestGames(GameType.wrap(0), start, 1);
assertEq(games.length, 1); assertEq(games.length, 1);
assertEq(games[0].index, 31); // The type 0 game should be the second to last one added.
assertEq(games[0].index, start - 1);
(gameType, createdAt, game) = games[0].metadata.unpack(); (gameType, createdAt, game) = games[0].metadata.unpack();
assertEq(gameType.raw(), 1); assertEq(gameType.raw(), 0);
assertEq(createdAt.raw(), block.timestamp); assertEq(createdAt.raw(), block.timestamp);
games = disputeGameFactory.findLatestGames(GameType.wrap(2), gameCount - 1, 1); // Find type 2 games.
games = disputeGameFactory.findLatestGames(GameType.wrap(2), start, 1);
assertEq(games.length, 1); assertEq(games.length, 1);
assertEq(games[0].index, 29); // The type 2 game should be the third to last one added.
assertEq(games[0].index, start - 2);
(gameType, createdAt, game) = games[0].metadata.unpack(); (gameType, createdAt, game) = games[0].metadata.unpack();
assertEq(gameType.raw(), 2); assertEq(gameType.raw(), 2);
assertEq(createdAt.raw(), block.timestamp); assertEq(createdAt.raw(), block.timestamp);
...@@ -309,10 +324,13 @@ contract DisputeGameFactory_FindLatestGames_Test is DisputeGameFactory_Init { ...@@ -309,10 +324,13 @@ contract DisputeGameFactory_FindLatestGames_Test is DisputeGameFactory_Init {
games = disputeGameFactory.findLatestGames(GameType.wrap(2), gameCount - 1, 5); games = disputeGameFactory.findLatestGames(GameType.wrap(2), gameCount - 1, 5);
assertEq(games.length, 0); assertEq(games.length, 0);
games = disputeGameFactory.findLatestGames(GameType.wrap(1), gameCount - 1, 5); // Forked network will have an indefinite, but very large number of games, so we skip this test when forking.
assertEq(games.length, 2); if (!isForkTest()) {
assertEq(games[0].index, 1); games = disputeGameFactory.findLatestGames(GameType.wrap(1), gameCount - 1, 5);
assertEq(games[1].index, 0); assertEq(games.length, 2);
assertEq(games[0].index, 1);
assertEq(games[1].index, 0);
}
} }
/// @dev Tests that the expected number of games are returned when `findLatestGames` is called. /// @dev Tests that the expected number of games are returned when `findLatestGames` is called.
......
...@@ -48,7 +48,9 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init { ...@@ -48,7 +48,9 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init {
function init(Claim rootClaim, Claim absolutePrestate, uint256 l2BlockNumber) public { function init(Claim rootClaim, Claim absolutePrestate, uint256 l2BlockNumber) public {
// Set the time to a realistic date. // Set the time to a realistic date.
vm.warp(1690906994); if (!isForkTest()) {
vm.warp(1690906994);
}
// Set the extra data for the game creation // Set the extra data for the game creation
extraData = abi.encode(l2BlockNumber); extraData = abi.encode(l2BlockNumber);
...@@ -93,8 +95,11 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init { ...@@ -93,8 +95,11 @@ contract FaultDisputeGame_Init is DisputeGameFactory_Init {
// Register the game implementation with the factory. // Register the game implementation with the factory.
disputeGameFactory.setImplementation(GAME_TYPE, gameImpl); disputeGameFactory.setImplementation(GAME_TYPE, gameImpl);
uint256 bondAmount = disputeGameFactory.initBonds(GAME_TYPE);
// Create a new game. // Create a new game.
gameProxy = IFaultDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, rootClaim, extraData)))); gameProxy = IFaultDisputeGame(
payable(address(disputeGameFactory.create{ value: bondAmount }(GAME_TYPE, rootClaim, extraData)))
);
// Check immutables // Check immutables
assertEq(gameProxy.gameType().raw(), GAME_TYPE.raw()); assertEq(gameProxy.gameType().raw(), GAME_TYPE.raw());
......
...@@ -37,8 +37,13 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init { ...@@ -37,8 +37,13 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init {
event Move(uint256 indexed parentIndex, Claim indexed pivot, address indexed claimant); event Move(uint256 indexed parentIndex, Claim indexed pivot, address indexed claimant);
function init(Claim rootClaim, Claim absolutePrestate, uint256 l2BlockNumber) public { function init(Claim rootClaim, Claim absolutePrestate, uint256 l2BlockNumber) public {
// Set the time to a realistic date. if (isForkTest()) {
vm.warp(1690906994); // Fund the proposer on this fork.
vm.deal(PROPOSER, 100 ether);
} else {
// Set the time to a realistic date.
vm.warp(1690906994);
}
// Set the extra data for the game creation // Set the extra data for the game creation
extraData = abi.encode(l2BlockNumber); extraData = abi.encode(l2BlockNumber);
...@@ -88,10 +93,18 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init { ...@@ -88,10 +93,18 @@ contract PermissionedDisputeGame_Init is DisputeGameFactory_Init {
); );
// Register the game implementation with the factory. // Register the game implementation with the factory.
disputeGameFactory.setImplementation(GAME_TYPE, gameImpl); disputeGameFactory.setImplementation(GAME_TYPE, gameImpl);
// Create a new game. // Create a new game.
uint256 bondAmount = disputeGameFactory.initBonds(GAME_TYPE);
vm.mockCall(
address(anchorStateRegistry),
abi.encodeCall(anchorStateRegistry.anchors, (GAME_TYPE)),
abi.encode(rootClaim, 0)
);
vm.prank(PROPOSER, PROPOSER); vm.prank(PROPOSER, PROPOSER);
gameProxy = gameProxy = IPermissionedDisputeGame(
IPermissionedDisputeGame(payable(address(disputeGameFactory.create(GAME_TYPE, rootClaim, extraData)))); payable(address(disputeGameFactory.create{ value: bondAmount }(GAME_TYPE, rootClaim, extraData)))
);
// Check immutables // Check immutables
assertEq(gameProxy.proposer(), PROPOSER); assertEq(gameProxy.proposer(), PROPOSER);
...@@ -128,22 +141,26 @@ contract PermissionedDisputeGame_Test is PermissionedDisputeGame_Init { ...@@ -128,22 +141,26 @@ contract PermissionedDisputeGame_Test is PermissionedDisputeGame_Init {
absolutePrestate = _changeClaimStatus(Claim.wrap(keccak256(absolutePrestateData)), VMStatuses.UNFINISHED); absolutePrestate = _changeClaimStatus(Claim.wrap(keccak256(absolutePrestateData)), VMStatuses.UNFINISHED);
super.setUp(); super.setUp();
super.init({ rootClaim: ROOT_CLAIM, absolutePrestate: absolutePrestate, l2BlockNumber: 0x10 }); super.init({ rootClaim: ROOT_CLAIM, absolutePrestate: absolutePrestate, l2BlockNumber: 0x10 });
} }
/// @dev Tests that the proposer can create a permissioned dispute game. /// @dev Tests that the proposer can create a permissioned dispute game.
function test_createGame_proposer_succeeds() public { function test_createGame_proposer_succeeds() public {
uint256 bondAmount = disputeGameFactory.initBonds(GAME_TYPE);
vm.prank(PROPOSER, PROPOSER); vm.prank(PROPOSER, PROPOSER);
disputeGameFactory.create(GAME_TYPE, ROOT_CLAIM, abi.encode(0x420)); disputeGameFactory.create{ value: bondAmount }(GAME_TYPE, ROOT_CLAIM, abi.encode(0x420));
} }
/// @dev Tests that the permissioned game cannot be created by any address other than the proposer. /// @dev Tests that the permissioned game cannot be created by any address other than the proposer.
function testFuzz_createGame_notProposer_reverts(address _p) public { function testFuzz_createGame_notProposer_reverts(address _p) public {
vm.assume(_p != PROPOSER); vm.assume(_p != PROPOSER);
uint256 bondAmount = disputeGameFactory.initBonds(GAME_TYPE);
vm.deal(_p, bondAmount);
vm.prank(_p, _p); vm.prank(_p, _p);
vm.expectRevert(BadAuth.selector); vm.expectRevert(BadAuth.selector);
disputeGameFactory.create(GAME_TYPE, ROOT_CLAIM, abi.encode(0x420)); disputeGameFactory.create{ value: bondAmount }(GAME_TYPE, ROOT_CLAIM, abi.encode(0x420));
} }
/// @dev Tests that the challenger can participate in a permissioned dispute game. /// @dev Tests that the challenger can participate in a permissioned dispute game.
......
...@@ -17,6 +17,7 @@ import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol"; ...@@ -17,6 +17,7 @@ import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
// Libraries // Libraries
import { Constants } from "src/libraries/Constants.sol"; import { Constants } from "src/libraries/Constants.sol";
import { console } from "forge-std/console.sol";
// Interfaces // Interfaces
import { IOptimismMintableERC20Full } from "interfaces/universal/IOptimismMintableERC20Full.sol"; import { IOptimismMintableERC20Full } from "interfaces/universal/IOptimismMintableERC20Full.sol";
...@@ -42,17 +43,19 @@ contract CommonTest is Test, Setup, Events { ...@@ -42,17 +43,19 @@ contract CommonTest is Test, Setup, Events {
IOptimismMintableERC20Full L2Token; IOptimismMintableERC20Full L2Token;
ILegacyMintableERC20Full LegacyL2Token; ILegacyMintableERC20Full LegacyL2Token;
ERC20 NativeL2Token; ERC20 NativeL2Token;
ERC20 BadL2Token;
IOptimismMintableERC20Full RemoteL1Token; IOptimismMintableERC20Full RemoteL1Token;
function setUp() public virtual override { function setUp() public virtual override {
// Setup.setup() may switch the tests over to a newly forked network. Therefore
// state modifying cheatcodes must be run after Setup.setup(), otherwise the
// changes will not be persisted into the new network.
Setup.setUp();
alice = makeAddr("alice"); alice = makeAddr("alice");
bob = makeAddr("bob"); bob = makeAddr("bob");
vm.deal(alice, 10000 ether); vm.deal(alice, 10000 ether);
vm.deal(bob, 10000 ether); vm.deal(bob, 10000 ether);
Setup.setUp();
// Override the config after the deploy script initialized the config // Override the config after the deploy script initialized the config
if (useAltDAOverride) { if (useAltDAOverride) {
deploy.cfg().setUseAltDA(true); deploy.cfg().setUseAltDA(true);
...@@ -68,7 +71,20 @@ contract CommonTest is Test, Setup, Events { ...@@ -68,7 +71,20 @@ contract CommonTest is Test, Setup, Events {
deploy.cfg().setUseInterop(true); deploy.cfg().setUseInterop(true);
} }
if (isForkTest()) {
// Skip any test suite which uses a nonstandard configuration.
if (useAltDAOverride || useLegacyContracts || customGasToken != address(0) || useInteropOverride) {
vm.skip(true);
}
} else {
// Modifying these values on a fork test causes issues.
vm.warp(deploy.cfg().l2OutputOracleStartingTimestamp() + 1);
vm.roll(deploy.cfg().l2OutputOracleStartingBlockNumber() + 1);
vm.fee(1 gwei);
}
vm.etch(address(ffi), vm.getDeployedCode("FFIInterface.sol:FFIInterface")); vm.etch(address(ffi), vm.getDeployedCode("FFIInterface.sol:FFIInterface"));
vm.allowCheatcodes(address(ffi));
vm.label(address(ffi), "FFIInterface"); vm.label(address(ffi), "FFIInterface");
// Exclude contracts for the invariant tests // Exclude contracts for the invariant tests
...@@ -76,13 +92,6 @@ contract CommonTest is Test, Setup, Events { ...@@ -76,13 +92,6 @@ contract CommonTest is Test, Setup, Events {
excludeContract(address(deploy)); excludeContract(address(deploy));
excludeContract(address(deploy.cfg())); excludeContract(address(deploy.cfg()));
// Make sure the base fee is non zero
vm.fee(1 gwei);
// Set sane initialize block numbers
vm.warp(deploy.cfg().l2OutputOracleStartingTimestamp() + 1);
vm.roll(deploy.cfg().l2OutputOracleStartingBlockNumber() + 1);
// Deploy L1 // Deploy L1
Setup.L1(); Setup.L1();
// Deploy L2 // Deploy L2
...@@ -113,22 +122,19 @@ contract CommonTest is Test, Setup, Events { ...@@ -113,22 +122,19 @@ contract CommonTest is Test, Setup, Events {
); );
vm.label(address(LegacyL2Token), "LegacyMintableERC20"); vm.label(address(LegacyL2Token), "LegacyMintableERC20");
// Deploy the L2 ERC20 now if (isForkTest()) {
L2Token = IOptimismMintableERC20Full( console.log("CommonTest: fork test detected, skipping L2 setup");
l2OptimismMintableERC20Factory.createStandardL2Token( L2Token = IOptimismMintableERC20Full(makeAddr("L2Token"));
address(L1Token), } else {
string(abi.encodePacked("L2-", L1Token.name())), // Deploy the L2 ERC20 now
string(abi.encodePacked("L2-", L1Token.symbol())) L2Token = IOptimismMintableERC20Full(
) l2OptimismMintableERC20Factory.createStandardL2Token(
); address(L1Token),
string(abi.encodePacked("L2-", L1Token.name())),
BadL2Token = ERC20( string(abi.encodePacked("L2-", L1Token.symbol()))
l2OptimismMintableERC20Factory.createStandardL2Token( )
address(1), );
string(abi.encodePacked("L2-", L1Token.name())), }
string(abi.encodePacked("L2-", L1Token.symbol()))
)
);
NativeL2Token = new ERC20("Native L2 Token", "L2T"); NativeL2Token = new ERC20("Native L2 Token", "L2T");
......
...@@ -7,6 +7,7 @@ import { Vm } from "forge-std/Vm.sol"; ...@@ -7,6 +7,7 @@ import { Vm } from "forge-std/Vm.sol";
// Scripts // Scripts
import { Deploy } from "scripts/deploy/Deploy.s.sol"; import { Deploy } from "scripts/deploy/Deploy.s.sol";
import { Upgrade } from "test/setup/Upgrade.s.sol";
import { Fork, LATEST_FORK } from "scripts/libraries/Config.sol"; import { Fork, LATEST_FORK } from "scripts/libraries/Config.sol";
import { L2Genesis, L1Dependencies } from "scripts/L2Genesis.s.sol"; import { L2Genesis, L1Dependencies } from "scripts/L2Genesis.s.sol";
import { OutputMode, Fork, ForkUtils } from "scripts/libraries/Config.sol"; import { OutputMode, Fork, ForkUtils } from "scripts/libraries/Config.sol";
...@@ -15,6 +16,7 @@ import { OutputMode, Fork, ForkUtils } from "scripts/libraries/Config.sol"; ...@@ -15,6 +16,7 @@ import { OutputMode, Fork, ForkUtils } from "scripts/libraries/Config.sol";
import { Predeploys } from "src/libraries/Predeploys.sol"; import { Predeploys } from "src/libraries/Predeploys.sol";
import { Preinstalls } from "src/libraries/Preinstalls.sol"; import { Preinstalls } from "src/libraries/Preinstalls.sol";
import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol"; import { AddressAliasHelper } from "src/vendor/AddressAliasHelper.sol";
import { Chains } from "scripts/libraries/Chains.sol";
// Interfaces // Interfaces
import { IOptimismPortal } from "interfaces/L1/IOptimismPortal.sol"; import { IOptimismPortal } from "interfaces/L1/IOptimismPortal.sol";
...@@ -68,9 +70,12 @@ contract Setup { ...@@ -68,9 +70,12 @@ contract Setup {
L2Genesis internal constant l2Genesis = L2Genesis internal constant l2Genesis =
L2Genesis(address(uint160(uint256(keccak256(abi.encode("optimism.l2genesis")))))); L2Genesis(address(uint160(uint256(keccak256(abi.encode("optimism.l2genesis"))))));
// @notice Allows users of Setup to override what L2 genesis is being created. /// @notice Allows users of Setup to override what L2 genesis is being created.
Fork l2Fork = LATEST_FORK; Fork l2Fork = LATEST_FORK;
/// @notice Indicates whether a test is running against a forked production network.
bool private _isForkTest;
// L1 contracts // L1 contracts
IDisputeGameFactory disputeGameFactory; IDisputeGameFactory disputeGameFactory;
IAnchorStateRegistry anchorStateRegistry; IAnchorStateRegistry anchorStateRegistry;
...@@ -112,24 +117,67 @@ contract Setup { ...@@ -112,24 +117,67 @@ contract Setup {
IOptimismSuperchainERC20Factory l2OptimismSuperchainERC20Factory = IOptimismSuperchainERC20Factory l2OptimismSuperchainERC20Factory =
IOptimismSuperchainERC20Factory(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY); IOptimismSuperchainERC20Factory(Predeploys.OPTIMISM_SUPERCHAIN_ERC20_FACTORY);
/// @dev Deploys the Deploy contract without including its bytecode in the bytecode /// @notice Indicates whether a test is running against a forked production network.
/// of this contract by fetching the bytecode dynamically using `vm.getCode()`. function isForkTest() public view returns (bool) {
/// If the Deploy bytecode is included in this contract, then it will double return _isForkTest;
}
/// @dev Deploys either the Deploy.s.sol or Upgrade.s.sol contract, by fetching the bytecode dynamically using
/// `vm.getDeployedCode()` and etching it into the state.
/// This enables us to avoid including the bytecode of those contracts in the bytecode of this contract.
/// If the bytecode of those contracts was included in this contract, then it will double
/// the compile time and bloat all of the test contract artifacts since they /// the compile time and bloat all of the test contract artifacts since they
/// will also need to include the bytecode for the Deploy contract. /// will also need to include the bytecode for the Deploy contract.
/// This is a hack as we are pushing solidity to the edge. /// This is a hack as we are pushing solidity to the edge.
function setUp() public virtual { function setUp() public virtual {
console.log("L1 setup start!"); console.log("Setup: L1 setup start!");
vm.etch(address(deploy), vm.getDeployedCode("Deploy.s.sol:Deploy")); if (vm.envOr("UPGRADE_TEST", false)) {
string memory forkUrl = vm.envString("FORK_RPC_URL");
_isForkTest = true;
vm.createSelectFork(forkUrl, vm.envUint("FORK_BLOCK_NUMBER"));
require(
block.chainid == Chains.Sepolia || block.chainid == Chains.Mainnet,
"Setup: ETH_RPC_URL must be set to a production (Sepolia or Mainnet) RPC URL"
);
vm.etch(address(deploy), vm.getDeployedCode("Upgrade.s.sol:Upgrade"));
} else {
vm.etch(address(deploy), vm.getDeployedCode("Deploy.s.sol:Deploy"));
}
vm.allowCheatcodes(address(deploy)); vm.allowCheatcodes(address(deploy));
deploy.setUp(); deploy.setUp();
console.log("L1 setup done!");
console.log("L2 setup start!"); console.log("Setup: L1 setup done!");
vm.etch(address(l2Genesis), vm.getDeployedCode("L2Genesis.s.sol:L2Genesis"));
vm.allowCheatcodes(address(l2Genesis)); if (_isForkTest) {
l2Genesis.setUp(); console.log("Setup: fork test detected, skipping L2 setup");
console.log("L2 setup done!"); } else {
console.log("Setup: L2 setup start!");
vm.etch(address(l2Genesis), vm.getDeployedCode("L2Genesis.s.sol:L2Genesis"));
vm.allowCheatcodes(address(l2Genesis));
l2Genesis.setUp();
console.log("Setup: L2 setup done!");
}
}
/// @dev Skips tests when running against a forked production network.
function skipIfForkTest(string memory message) public {
if (_isForkTest) {
vm.skip(true);
console.log(string.concat("Skipping fork test: ", message));
}
}
/// @dev Returns early when running against a forked production network. Useful for allowing a portion of a test
/// to run.
function returnIfForkTest(string memory message) public view {
if (_isForkTest) {
console.log(string.concat("Returning early from fork test: ", message));
assembly {
return(0, 0)
}
}
} }
/// @dev Sets up the L1 contracts. /// @dev Sets up the L1 contracts.
...@@ -180,6 +228,7 @@ contract Setup { ...@@ -180,6 +228,7 @@ contract Setup {
vm.label(deploy.mustGetAddress("ProtocolVersionsProxy"), "ProtocolVersionsProxy"); vm.label(deploy.mustGetAddress("ProtocolVersionsProxy"), "ProtocolVersionsProxy");
vm.label(address(superchainConfig), "SuperchainConfig"); vm.label(address(superchainConfig), "SuperchainConfig");
vm.label(deploy.mustGetAddress("SuperchainConfigProxy"), "SuperchainConfigProxy"); vm.label(deploy.mustGetAddress("SuperchainConfigProxy"), "SuperchainConfigProxy");
vm.label(address(anchorStateRegistry), "AnchorStateRegistryProxy");
vm.label(AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)), "L1CrossDomainMessenger_aliased"); vm.label(AddressAliasHelper.applyL1ToL2Alias(address(l1CrossDomainMessenger)), "L1CrossDomainMessenger_aliased");
if (!deploy.cfg().useFaultProofs()) { if (!deploy.cfg().useFaultProofs()) {
...@@ -199,6 +248,12 @@ contract Setup { ...@@ -199,6 +248,12 @@ contract Setup {
/// @dev Sets up the L2 contracts. Depends on `L1()` being called first. /// @dev Sets up the L2 contracts. Depends on `L1()` being called first.
function L2() public { function L2() public {
// Fork tests focus on L1 contracts so there is no need to do all the work of setting up L2.
if (_isForkTest) {
console.log("Setup: fork test detected, skipping L2 setup");
return;
}
console.log("Setup: creating L2 genesis with fork %s", l2Fork.toString()); console.log("Setup: creating L2 genesis with fork %s", l2Fork.toString());
l2Genesis.runWithOptions( l2Genesis.runWithOptions(
OutputMode.NONE, OutputMode.NONE,
......
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// Testing
import { stdJson } from "forge-std/StdJson.sol";
// Scripts
import { Deployer } from "scripts/deploy/Deployer.sol";
// Libraries
import { GameTypes } from "src/dispute/lib/Types.sol";
import { EIP1967Helper } from "test/mocks/EIP1967Helper.sol";
// Interfaces
import { IFaultDisputeGame } from "interfaces/dispute/IFaultDisputeGame.sol";
import { IDisputeGameFactory } from "interfaces/dispute/IDisputeGameFactory.sol";
import { IAddressManager } from "interfaces/legacy/IAddressManager.sol";
/// @title Upgrade
/// @notice This script is called by Setup.sol as a preparation step for the foundry test suite, and is run as an
/// alternative to Deploy.s.sol, when `UPGRADE_TEST=true` is set in the env.
/// Like Deploy.s.sol this script saves the system addresses to disk so that they can be read into memory later
/// on, however rather than deploying new contracts from the local source code, it simply reads the addresses
/// from the superchain-registry.
/// Therefore this script can only be run against a fork of a production network which is listed in the
/// superchain-registry.
/// This contract must not have constructor logic because it is set into state using `etch`.
contract Upgrade is Deployer {
using stdJson for string;
/// @notice Returns the base chain name to use for forking
/// @return The base chain name as a string
function upgradeBaseChain() internal view returns (string memory) {
return vm.envOr("UPGRADE_BASE_CHAIN", string("mainnet"));
}
/// @notice Returns the OP chain name to use for forking
/// @return The OP chain name as a string
function upgradeOpChain() internal view returns (string memory) {
return vm.envOr("UPGRADE_OP_CHAIN", string("op"));
}
/// @notice Reads a standard chains addresses from the superchain-registry and saves them to disk.
function run() public {
string memory superchainBasePath = "./lib/superchain-registry/superchain/configs/";
// Read the superchain config files
// During development of an upgrade which adds a new contract, the contract will not yet be present in the
// superchain-registry. In this case, the contract will be deployed by the upgrade process, and will need to
// be saved by after the call to opcm.upgrade().
// After the upgrade is complete, the superchain-registry will be updated and the contract will be present.
// At this point, the test will need to be updated to read the new contract from the superchain-registry using
// either the `saveProxyAndImpl` or `save` functions.
string memory superchainToml =
vm.readFile(string.concat(superchainBasePath, upgradeBaseChain(), "/superchain.toml"));
string memory opToml =
vm.readFile(string.concat(superchainBasePath, upgradeBaseChain(), "/", upgradeOpChain(), ".toml"));
// Superchain shared contracts
saveProxyAndImpl("SuperchainConfig", superchainToml, ".superchain_config_addr");
saveProxyAndImpl("ProtocolVersions", superchainToml, ".protocol_versions_addr");
save("OPContractsManager", vm.parseTomlAddress(superchainToml, ".op_contracts_manager_proxy_addr"));
// Core contracts
save("ProxyAdmin", vm.parseTomlAddress(opToml, ".addresses.ProxyAdmin"));
saveProxyAndImpl("SystemConfig", opToml, ".addresses.SystemConfigProxy");
// Bridge contracts
address optimismPortal = vm.parseTomlAddress(opToml, ".addresses.OptimismPortalProxy");
save("OptimismPortalProxy", optimismPortal);
save("OptimismPortal", EIP1967Helper.getImplementation(optimismPortal));
save("OptimismPortal2", EIP1967Helper.getImplementation(optimismPortal));
address addressManager = vm.parseTomlAddress(opToml, ".addresses.AddressManager");
save("AddressManager", addressManager);
save("L1CrossDomainMessenger", IAddressManager(addressManager).getAddress("OVM_L1CrossDomainMessenger"));
save("L1CrossDomainMessengerProxy", vm.parseTomlAddress(opToml, ".addresses.L1CrossDomainMessengerProxy"));
saveProxyAndImpl("OptimismMintableERC20Factory", opToml, ".addresses.OptimismMintableERC20FactoryProxy");
saveProxyAndImpl("L1StandardBridge", opToml, ".addresses.L1StandardBridgeProxy");
saveProxyAndImpl("L1ERC721Bridge", opToml, ".addresses.L1ERC721BridgeProxy");
// Fault proof proxied contracts
saveProxyAndImpl("AnchorStateRegistry", opToml, ".addresses.AnchorStateRegistryProxy");
saveProxyAndImpl("DisputeGameFactory", opToml, ".addresses.DisputeGameFactoryProxy");
saveProxyAndImpl("DelayedWETH", opToml, ".addresses.DelayedWETHProxy");
// Fault proof non-proxied contracts
save("PreimageOracle", vm.parseTomlAddress(opToml, ".addresses.PreimageOracle"));
save("Mips", vm.parseTomlAddress(opToml, ".addresses.MIPS"));
IDisputeGameFactory disputeGameFactory = IDisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
save("FaultDisputeGame", vm.parseTomlAddress(opToml, ".addresses.FaultDisputeGame"));
// The PermissionedDisputeGame and PermissionedDelayedWETHProxy are not listed in the registry for OP, so we
// look it up onchain
IFaultDisputeGame permissionedDisputeGame =
IFaultDisputeGame(address(disputeGameFactory.gameImpls(GameTypes.PERMISSIONED_CANNON)));
save("PermissionedDisputeGame", address(permissionedDisputeGame));
save("PermissionedDelayedWETHProxy", address(permissionedDisputeGame.weth()));
}
/// @notice Saves the proxy and implementation addresses for a contract name
/// @param _contractName The name of the contract to save
/// @param _tomlPath The path to the superchain config file
/// @param _tomlKey The key in the superchain config file to get the proxy address
function saveProxyAndImpl(string memory _contractName, string memory _tomlPath, string memory _tomlKey) internal {
address proxy = vm.parseTomlAddress(_tomlPath, _tomlKey);
save(string.concat(_contractName, "Proxy"), proxy);
address impl = EIP1967Helper.getImplementation(proxy);
require(impl != address(0), "Upgrade: Implementation address is zero");
save(_contractName, impl);
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment