diff --git a/rvsol/foundry.toml b/rvsol/foundry.toml
index 6cc65bdf..e748f6cb 100644
--- a/rvsol/foundry.toml
+++ b/rvsol/foundry.toml
@@ -17,6 +17,7 @@ remappings = [
   # We need these remappings to use the Optimism monorepo contracts as a library.
   'src/dispute=lib/optimism/packages/contracts-bedrock/src/dispute',
   'src/libraries=lib/optimism/packages/contracts-bedrock/src/libraries',
+  'scripts/libraries=lib/optimism/packages/contracts-bedrock/scripts/libraries',
 
   # required for etherscan contract verification
   'src/L1=lib/optimism/packages/contracts-bedrock/src/L1',
diff --git a/rvsol/scripts/Deploy.s.sol b/rvsol/scripts/Deploy.s.sol
index 16c87db5..25a6462a 100644
--- a/rvsol/scripts/Deploy.s.sol
+++ b/rvsol/scripts/Deploy.s.sol
@@ -11,15 +11,29 @@ import { RISCV } from "../src/RISCV.sol";
 
 import { IBigStepper } from "@optimism/src/dispute/interfaces/IBigStepper.sol";
 import { IPreimageOracle } from "@optimism/src/cannon/interfaces/IPreimageOracle.sol";
-import { DisputeGameFactory } from "@optimism/src/dispute/DisputeGameFactory.sol";
-import { DelayedWETH } from "@optimism/src/dispute/weth/DelayedWETH.sol";
-import { AnchorStateRegistry } from "@optimism/src/dispute/AnchorStateRegistry.sol";
-import { FaultDisputeGame } from "@optimism/src/dispute/FaultDisputeGame.sol";
+import { IDisputeGameFactory } from "@optimism/src/dispute/interfaces/IDisputeGameFactory.sol";
+import { IDisputeGame } from "@optimism/src/dispute/interfaces/IDisputeGame.sol";
+import { IDelayedWETH } from "@optimism/src/dispute/interfaces/IDelayedWETH.sol";
+import { IAnchorStateRegistry } from "@optimism/src/dispute/interfaces/IAnchorStateRegistry.sol";
 import { GnosisSafe as Safe } from "safe-contracts/GnosisSafe.sol";
 import { Enum as SafeOps } from "safe-contracts/common/Enum.sol";
 import "@optimism/src/dispute/lib/Types.sol";
 
 contract Deploy is Deployer {
+    /// @notice FaultDisputeGameParams is a struct that contains the parameters necessary to call
+    ///         the function _setFaultGameImplementation. This struct exists because the EVM needs
+    ///         to finally adopt PUSHN and get rid of stack too deep once and for all.
+    ///         Someday we will look back and laugh about stack too deep, today is not that day.
+    struct FaultDisputeGameParams {
+        IAnchorStateRegistry anchorStateRegistry;
+        IDelayedWETH weth;
+        GameType gameType;
+        Claim absolutePrestate;
+        IBigStepper faultVm;
+        uint256 maxGameDepth;
+        Duration maxClockDuration;
+    }
+
     /// @notice Modifier that wraps a function in broadcasting.
     modifier broadcast() {
         vm.startBroadcast(msg.sender);
@@ -111,36 +125,103 @@ contract Deploy is Deployer {
     /// @notice Sets the implementation for the given fault game type in the `DisputeGameFactory`.
     function setAsteriscFaultGameImplementation(bool _allowUpgrade) public broadcast {
         console.log("Setting Asterisc FaultDisputeGame implementation");
-        DisputeGameFactory factory = DisputeGameFactory(mustGetChainAddress("DisputeGameFactoryProxy"));
-        DelayedWETH weth = DelayedWETH(mustGetChainAddress("DelayedWETHProxy"));
-        AnchorStateRegistry anchorStateRegistry = AnchorStateRegistry(mustGetChainAddress("AnchorStateRegistryProxy"));
+        IDisputeGameFactory factory = IDisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
+        IDelayedWETH weth = IDelayedWETH(mustGetAddress("DelayedWETHProxy"));
+
+        // Set the Asterisc FaultDisputeGame implementation in the factory.
+        _setFaultGameImplementation({
+            _factory: factory,
+            _allowUpgrade: _allowUpgrade,
+            _params: FaultDisputeGameParams({
+                anchorStateRegistry: IAnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
+                weth: weth,
+                gameType: GameTypes.ASTERISC,
+                absolutePrestate: loadRiscvAbsolutePrestate(),
+                faultVm: IBigStepper(mustGetAddress("RISCV")),
+                maxGameDepth: cfg.faultGameMaxDepth(),
+                maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration()))
+            })
+        });
+    }
 
-        if (address(factory.gameImpls(GameTypes.ASTERISC)) != address(0) && !_allowUpgrade) {
+    /// @notice Sets the implementation for the given fault game type in the `DisputeGameFactory`.
+    function _setFaultGameImplementation(
+        IDisputeGameFactory _factory,
+        bool _allowUpgrade,
+        FaultDisputeGameParams memory _params
+    )
+        internal
+    {
+        if (address(_factory.gameImpls(_params.gameType)) != address(0) && !_allowUpgrade) {
             console.log(
-                "[WARN] DisputeGameFactoryProxy: `FaultDisputeGame` implementation already set for game type: ASTERISC"
+                "[WARN] DisputeGameFactoryProxy: `FaultDisputeGame` implementation already set for game type: %s",
+                vm.toString(GameType.unwrap(_params.gameType))
             );
             return;
         }
 
-        FaultDisputeGame fdg = new FaultDisputeGame{ salt: _implSalt() }({
-            _gameType: GameTypes.ASTERISC,
-            _absolutePrestate: loadRiscvAbsolutePrestate(),
-            _maxGameDepth: cfg.faultGameMaxDepth(),
-            _splitDepth: cfg.faultGameSplitDepth(),
-            _clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
-            _maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
-            _vm: IBigStepper(mustGetAddress("RISCV")),
-            _weth: weth,
-            _anchorStateRegistry: anchorStateRegistry,
-            _l2ChainId: cfg.l2ChainID()
-        });
+        uint32 rawGameType = GameType.unwrap(_params.gameType);
+        _factory.setImplementation(
+            _params.gameType,
+            IDisputeGame(
+                _deploy(
+                    "RISCV",
+                    abi.encode(
+                        _params.gameType,
+                        _params.absolutePrestate,
+                        _params.maxGameDepth,
+                        cfg.faultGameSplitDepth(),
+                        cfg.faultGameClockExtension(),
+                        _params.maxClockDuration,
+                        _params.faultVm,
+                        _params.weth,
+                        _params.anchorStateRegistry,
+                        cfg.l2ChainID(),
+                        cfg.l2OutputOracleProposer(),
+                        cfg.l2OutputOracleChallenger()
+                    )
+                )
+            )
+        );
 
-        bytes memory data = abi.encodeCall(DisputeGameFactory.setImplementation, (GameTypes.ASTERISC, fdg));
-        _callViaSafe(address(factory), data);
+        string memory gameTypeString = "Asterisc";
 
         console.log(
-            "DisputeGameFactoryProxy: set `FaultDisputeGame` implementation (Backend: ASTERISC | GameType: %s)",
-            vm.toString(GameType.unwrap(GameTypes.ASTERISC))
+            "DisputeGameFactoryProxy: set `FaultDisputeGame` implementation (Backend: %s | GameType: %s)",
+            gameTypeString,
+            vm.toString(rawGameType)
         );
     }
+
+    /// @notice Deploys a contract via CREATE2.
+    /// @param _name The name of the contract.
+    /// @param _constructorParams The constructor parameters.
+    function _deploy(string memory _name, bytes memory _constructorParams) internal returns (address addr_) {
+        return _deploy(_name, _name, _constructorParams);
+    }
+
+    /// @notice Deploys a contract via CREATE2.
+    /// @param _name The name of the contract.
+    /// @param _nickname The nickname of the contract.
+    /// @param _constructorParams The constructor parameters.
+    function _deploy(
+        string memory _name,
+        string memory _nickname,
+        bytes memory _constructorParams
+    )
+        internal
+        returns (address addr_)
+    {
+        console.log("Deploying %s", _nickname);
+        bytes32 salt = _implSalt();
+        bytes memory initCode = abi.encodePacked(vm.getCode(_name), _constructorParams);
+        address preComputedAddress = vm.computeCreate2Address(salt, keccak256(initCode));
+        require(preComputedAddress.code.length == 0, "Deploy: contract already deployed");
+        assembly {
+            addr_ := create2(0, add(initCode, 0x20), mload(initCode), salt)
+        }
+        require(addr_ != address(0), "deployment failed");
+        save(_nickname, addr_);
+        console.log("%s deployed at %s", _nickname, addr_);
+    }
 }
diff --git a/rvsol/scripts/Deploy_Stage_1_4.sol b/rvsol/scripts/Deploy_Stage_1_4.sol
index 565a6016..51969368 100644
--- a/rvsol/scripts/Deploy_Stage_1_4.sol
+++ b/rvsol/scripts/Deploy_Stage_1_4.sol
@@ -4,24 +4,42 @@ pragma solidity ^0.8.15;
 import { Config } from "scripts/lib/Config.sol";
 import { Deployer } from "scripts/lib/Deployer.sol";
 import { RISCV } from "../src/RISCV.sol";
-import { IPreimageOracle } from "@optimism/src/cannon/interfaces/IPreimageOracle.sol";
-import { DisputeGameFactory } from "@optimism/src/dispute/DisputeGameFactory.sol";
-import { DelayedWETH } from "@optimism/src/dispute/weth/DelayedWETH.sol";
-import { AnchorStateRegistry } from "@optimism/src/dispute/AnchorStateRegistry.sol";
-import { PreimageOracle } from "@optimism/src/cannon/PreimageOracle.sol";
-import { Types } from "@optimism/scripts/Types.sol";
+import { PreimageOracle } from "src/cannon/PreimageOracle.sol";
+import { ISuperchainConfig } from "src/L1/interfaces/ISuperchainConfig.sol";
+import { IPreimageOracle } from "src/cannon/interfaces/IPreimageOracle.sol";
+import { IDisputeGameFactory } from "src/dispute/interfaces/IDisputeGameFactory.sol";
+import { IFaultDisputeGame } from "src/dispute/interfaces/IFaultDisputeGame.sol";
+import { IDisputeGame } from "src/dispute/interfaces/IDisputeGame.sol";
+import { IDelayedWETH } from "src/dispute/interfaces/IDelayedWETH.sol";
+import { IAnchorStateRegistry } from "@optimism/src/dispute/interfaces/IAnchorStateRegistry.sol";
+import { ChainAssertions } from "@optimism/scripts/deploy/ChainAssertions.sol";
+import { Types } from "@optimism/scripts/libraries/Types.sol";
+
 import { ProxyAdmin } from "@optimism/src/universal/ProxyAdmin.sol";
 import { AddressManager } from "@optimism/src/legacy/AddressManager.sol";
 import { Proxy } from "@optimism/src/universal/Proxy.sol";
 import { EIP1967Helper } from "@optimism/test/mocks/EIP1967Helper.sol";
-import { FaultDisputeGame } from "@optimism/src/dispute/FaultDisputeGame.sol";
-import { Chains } from "@optimism/scripts/Chains.sol";
+import { Chains } from "@optimism/scripts/libraries/Chains.sol";
 import { IBigStepper } from "@optimism/src/dispute/interfaces/IBigStepper.sol";
 import "@optimism/src/dispute/lib/Types.sol";
 import { console2 as console } from "forge-std/console2.sol";
 import { StdAssertions } from "forge-std/StdAssertions.sol";
 
 contract Deploy is Deployer, StdAssertions {
+    /// @notice FaultDisputeGameParams is a struct that contains the parameters necessary to call
+    ///         the function _setFaultGameImplementation. This struct exists because the EVM needs
+    ///         to finally adopt PUSHN and get rid of stack too deep once and for all.
+    ///         Someday we will look back and laugh about stack too deep, today is not that day.
+    struct FaultDisputeGameParams {
+        IAnchorStateRegistry anchorStateRegistry;
+        IDelayedWETH weth;
+        GameType gameType;
+        Claim absolutePrestate;
+        IBigStepper faultVm;
+        uint256 maxGameDepth;
+        Duration maxClockDuration;
+    }
+
     /// @notice Modifier that wraps a function in broadcasting.
     modifier broadcast() {
         vm.startBroadcast(msg.sender);
@@ -57,6 +75,26 @@ contract Deploy is Deployer, StdAssertions {
         return keccak256(bytes(Config.implSalt()));
     }
 
+    /// @notice Returns the proxy addresses, not reverting if any are unset.
+    function _proxiesUnstrict() internal view returns (Types.ContractSet memory proxies_) {
+        proxies_ = Types.ContractSet({
+            L1CrossDomainMessenger: getAddress("L1CrossDomainMessengerProxy"),
+            L1StandardBridge: getAddress("L1StandardBridgeProxy"),
+            L2OutputOracle: getAddress("L2OutputOracleProxy"),
+            DisputeGameFactory: getAddress("DisputeGameFactoryProxy"),
+            DelayedWETH: getAddress("DelayedWETHProxy"),
+            PermissionedDelayedWETH: getAddress("PermissionedDelayedWETHProxy"),
+            AnchorStateRegistry: getAddress("AnchorStateRegistryProxy"),
+            OptimismMintableERC20Factory: getAddress("OptimismMintableERC20FactoryProxy"),
+            OptimismPortal: getAddress("OptimismPortalProxy"),
+            OptimismPortal2: getAddress("OptimismPortalProxy"),
+            SystemConfig: getAddress("SystemConfigProxy"),
+            L1ERC721Bridge: getAddress("L1ERC721BridgeProxy"),
+            ProtocolVersions: getAddress("ProtocolVersionsProxy"),
+            SuperchainConfig: getAddress("SuperchainConfigProxy")
+        });
+    }
+
     /// @notice Deploy RISCV
     function deployRiscv() public broadcast returns (address addr_) {
         console.log("Deploying RISCV implementation");
@@ -95,24 +133,21 @@ contract Deploy is Deployer, StdAssertions {
     /// @notice Deploy the DisputeGameFactory
     function deployDisputeGameFactory() public broadcast returns (address addr_) {
         console.log("Deploying DisputeGameFactory implementation");
-        DisputeGameFactory disputeGameFactory = new DisputeGameFactory{ salt: _implSalt() }();
-        save("DisputeGameFactory", address(disputeGameFactory));
-        console.log("DisputeGameFactory deployed at %s", address(disputeGameFactory));
+        IDisputeGameFactory factory = IDisputeGameFactory(_deploy("DisputeGameFactory", hex""));
 
-        // Check that the contract is initialized
-        assertSlotValueIsOne({ _contractAddress: address(disputeGameFactory), _slot: 0, _offset: 0 });
-        require(disputeGameFactory.owner() == address(0));
+        // Override the `DisputeGameFactory` contract to the deployed implementation. This is necessary to check the
+        // `DisputeGameFactory` implementation alongside dependent contracts, which are always proxies.
+        Types.ContractSet memory contracts = _proxiesUnstrict();
+        contracts.DisputeGameFactory = address(factory);
+        ChainAssertions.checkDisputeGameFactory({ _contracts: contracts, _expectedOwner: address(0) });
 
-        addr_ = address(disputeGameFactory);
+        addr_ = address(factory);
     }
 
     /// @notice Deploy the AnchorStateRegistry
     function deployAnchorStateRegistry() public broadcast returns (address addr_) {
-        console.log("Deploying AnchorStateRegistry implementation");
-        AnchorStateRegistry anchorStateRegistry =
-            new AnchorStateRegistry{ salt: _implSalt() }(DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy")));
-        save("AnchorStateRegistry", address(anchorStateRegistry));
-        console.log("AnchorStateRegistry deployed at %s", address(anchorStateRegistry));
+        IAnchorStateRegistry anchorStateRegistry =
+            IAnchorStateRegistry(_deploy("AnchorStateRegistry", abi.encode(mustGetAddress("DisputeGameFactoryProxy"))));
 
         addr_ = address(anchorStateRegistry);
     }
@@ -133,15 +168,15 @@ contract Deploy is Deployer, StdAssertions {
         _upgradeAndCall({
             _proxy: payable(disputeGameFactoryProxy),
             _implementation: disputeGameFactory,
-            _innerCallData: abi.encodeCall(DisputeGameFactory.initialize, (msg.sender))
+            _innerCallData: abi.encodeCall(IDisputeGameFactory.initialize, (msg.sender))
         });
 
-        string memory version = DisputeGameFactory(disputeGameFactoryProxy).version();
+        string memory version = IDisputeGameFactory(disputeGameFactoryProxy).version();
         console.log("DisputeGameFactory version: %s", version);
 
         // Check that the contract is initialized
         assertSlotValueIsOne({ _contractAddress: address(disputeGameFactoryProxy), _slot: 0, _offset: 0 });
-        require(DisputeGameFactory(disputeGameFactoryProxy).owner() == msg.sender);
+        require(IDisputeGameFactory(disputeGameFactoryProxy).owner() == msg.sender);
     }
 
     // @notice Initialize the AnchorStateRegistry
@@ -150,9 +185,10 @@ contract Deploy is Deployer, StdAssertions {
         console.log("Upgrading and initializing AnchorStateRegistry");
         address anchorStateRegistryProxy = mustGetAddress("AnchorStateRegistryProxy");
         address anchorStateRegistry = mustGetAddress("AnchorStateRegistry");
+        ISuperchainConfig superchainConfig = ISuperchainConfig(mustGetAddress("SuperchainConfigProxy"));
 
-        AnchorStateRegistry.StartingAnchorRoot[] memory roots = new AnchorStateRegistry.StartingAnchorRoot[](1);
-        roots[0] = AnchorStateRegistry.StartingAnchorRoot({
+        IAnchorStateRegistry.StartingAnchorRoot[] memory roots = new IAnchorStateRegistry.StartingAnchorRoot[](1);
+        roots[0] = IAnchorStateRegistry.StartingAnchorRoot({
             gameType: GameTypes.ASTERISC,
             outputRoot: OutputRoot({
                 root: Hash.wrap(cfg.faultGameGenesisOutputRoot()),
@@ -163,10 +199,10 @@ contract Deploy is Deployer, StdAssertions {
         _upgradeAndCall({
             _proxy: payable(anchorStateRegistryProxy),
             _implementation: anchorStateRegistry,
-            _innerCallData: abi.encodeCall(AnchorStateRegistry.initialize, (roots))
+            _innerCallData: abi.encodeCall(IAnchorStateRegistry.initialize, (roots, superchainConfig))
         });
 
-        string memory version = AnchorStateRegistry(payable(anchorStateRegistryProxy)).version();
+        string memory version = IAnchorStateRegistry(payable(anchorStateRegistryProxy)).version();
         console.log("AnchorStateRegistry version: %s", version);
     }
 
@@ -245,43 +281,108 @@ contract Deploy is Deployer, StdAssertions {
     /// @notice Sets the implementation for the given fault game type in the `DisputeGameFactory`.
     function setAsteriscFaultGameImplementation(bool _allowUpgrade) public broadcast {
         console.log("Setting Asterisc FaultDisputeGame implementation");
-        DelayedWETH weth = DelayedWETH(mustGetChainAddress("DelayedWETHProxy"));
-        // use freshly deployed factory and anchorStateRegister
-        DisputeGameFactory factory = DisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
-        AnchorStateRegistry anchorStateRegistry = AnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy"));
+        IDisputeGameFactory factory = IDisputeGameFactory(mustGetAddress("DisputeGameFactoryProxy"));
+        IDelayedWETH weth = IDelayedWETH(mustGetAddress("DelayedWETHProxy"));
+
+        // Set the Asterisc FaultDisputeGame implementation in the factory.
+        _setFaultGameImplementation({
+            _factory: factory,
+            _allowUpgrade: _allowUpgrade,
+            _params: FaultDisputeGameParams({
+                anchorStateRegistry: IAnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy")),
+                weth: weth,
+                gameType: GameTypes.ASTERISC,
+                absolutePrestate: loadRiscvAbsolutePrestate(),
+                faultVm: IBigStepper(mustGetAddress("RISCV")),
+                maxGameDepth: cfg.faultGameMaxDepth(),
+                maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration()))
+            })
+        });
+    }
 
-        if (address(factory.gameImpls(GameTypes.ASTERISC)) != address(0) && !_allowUpgrade) {
+    /// @notice Sets the implementation for the given fault game type in the `DisputeGameFactory`.
+    function _setFaultGameImplementation(
+        IDisputeGameFactory _factory,
+        bool _allowUpgrade,
+        FaultDisputeGameParams memory _params
+    )
+        internal
+    {
+        if (address(_factory.gameImpls(_params.gameType)) != address(0) && !_allowUpgrade) {
             console.log(
-                "[WARN] DisputeGameFactoryProxy: `FaultDisputeGame` implementation already set for game type: ASTERISC"
+                "[WARN] DisputeGameFactoryProxy: `FaultDisputeGame` implementation already set for game type: %s",
+                vm.toString(GameType.unwrap(_params.gameType))
             );
             return;
         }
 
-        FaultDisputeGame fdg = new FaultDisputeGame{ salt: _implSalt() }({
-            _gameType: GameTypes.ASTERISC,
-            _absolutePrestate: loadRiscvAbsolutePrestate(),
-            _maxGameDepth: cfg.faultGameMaxDepth(),
-            _splitDepth: cfg.faultGameSplitDepth(),
-            _clockExtension: Duration.wrap(uint64(cfg.faultGameClockExtension())),
-            _maxClockDuration: Duration.wrap(uint64(cfg.faultGameMaxClockDuration())),
-            _vm: IBigStepper(mustGetAddress("RISCV")),
-            _weth: weth,
-            _anchorStateRegistry: anchorStateRegistry,
-            _l2ChainId: cfg.l2ChainID()
-        });
+        uint32 rawGameType = GameType.unwrap(_params.gameType);
+        _factory.setImplementation(
+            _params.gameType,
+            IDisputeGame(
+                _deploy(
+                    "RISCV",
+                    abi.encode(
+                        _params.gameType,
+                        _params.absolutePrestate,
+                        _params.maxGameDepth,
+                        cfg.faultGameSplitDepth(),
+                        cfg.faultGameClockExtension(),
+                        _params.maxClockDuration,
+                        _params.faultVm,
+                        _params.weth,
+                        _params.anchorStateRegistry,
+                        cfg.l2ChainID(),
+                        cfg.l2OutputOracleProposer(),
+                        cfg.l2OutputOracleChallenger()
+                    )
+                )
+            )
+        );
 
-        factory.setImplementation(GameTypes.ASTERISC, fdg);
+        string memory gameTypeString = "Asterisc";
 
         console.log(
-            "DisputeGameFactoryProxy: set `FaultDisputeGame` implementation (Backend: ASTERISC | GameType: %s)",
-            vm.toString(GameType.unwrap(GameTypes.ASTERISC))
+            "DisputeGameFactoryProxy: set `FaultDisputeGame` implementation (Backend: %s | GameType: %s)",
+            gameTypeString,
+            vm.toString(rawGameType)
         );
+    }
+
+    /// @notice Deploys a contract via CREATE2.
+    /// @param _name The name of the contract.
+    /// @param _constructorParams The constructor parameters.
+    function _deploy(string memory _name, bytes memory _constructorParams) internal returns (address addr_) {
+        return _deploy(_name, _name, _constructorParams);
+    }
 
-        factory.setInitBond(GameTypes.ASTERISC, 0.08 ether);
+    /// @notice Deploys a contract via CREATE2.
+    /// @param _name The name of the contract.
+    /// @param _nickname The nickname of the contract.
+    /// @param _constructorParams The constructor parameters.
+    function _deploy(
+        string memory _name,
+        string memory _nickname,
+        bytes memory _constructorParams
+    )
+        internal
+        returns (address addr_)
+    {
+        console.log("Deploying %s", _nickname);
+        bytes32 salt = _implSalt();
+        bytes memory initCode = abi.encodePacked(vm.getCode(_name), _constructorParams);
+        address preComputedAddress = vm.computeCreate2Address(salt, keccak256(initCode));
+        require(preComputedAddress.code.length == 0, "Deploy: contract already deployed");
+        assembly {
+            addr_ := create2(0, add(initCode, 0x20), mload(initCode), salt)
+        }
+        require(addr_ != address(0), "deployment failed");
+        save(_nickname, addr_);
+        console.log("%s deployed at %s", _nickname, addr_);
     }
 
     /// @notice Checks that the deployed system is configured correctly.
-    function postDeployAssertions() internal {
+    function postDeployAssertions() internal view {
         // Ensure that `useFaultProofs` is set to `true`.
         assertTrue(cfg.useFaultProofs());
 
@@ -290,10 +391,10 @@ contract Deploy is Deployer, StdAssertions {
 
         // Ensure the contracts are owned by the correct entities.
         address dgfProxyAddr = mustGetAddress("DisputeGameFactoryProxy");
-        DisputeGameFactory dgfProxy = DisputeGameFactory(dgfProxyAddr);
+        IDisputeGameFactory dgfProxy = IDisputeGameFactory(dgfProxyAddr);
         assertEq(address(dgfProxy.owner()), msg.sender);
 
-        PreimageOracle oracle = PreimageOracle(mustGetChainAddress("PreimageOracle"));
+        PreimageOracle oracle = PreimageOracle(mustGetAddress("PreimageOracle"));
         assertEq(oracle.minProposalSize(), cfg.preimageOracleMinProposalSize());
         assertEq(oracle.challengePeriod(), cfg.preimageOracleChallengePeriod());
 
@@ -301,13 +402,13 @@ contract Deploy is Deployer, StdAssertions {
         assertEq(address(riscv.oracle()), address(oracle));
 
         // Check the AnchorStateRegistry configuration.
-        AnchorStateRegistry asr = AnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy"));
+        IAnchorStateRegistry asr = IAnchorStateRegistry(mustGetAddress("AnchorStateRegistryProxy"));
         (Hash root, uint256 l2BlockNumber) = asr.anchors(GameTypes.ASTERISC);
         assertEq(root.raw(), cfg.faultGameGenesisOutputRoot());
         assertEq(l2BlockNumber, cfg.faultGameGenesisBlock());
 
         // Check the FaultDisputeGame configuration.
-        FaultDisputeGame gameImpl = FaultDisputeGame(payable(address(dgfProxy.gameImpls(GameTypes.ASTERISC))));
+        IFaultDisputeGame gameImpl = IFaultDisputeGame(payable(address(dgfProxy.gameImpls(GameTypes.ASTERISC))));
         assertEq(gameImpl.maxGameDepth(), cfg.faultGameMaxDepth());
         assertEq(gameImpl.splitDepth(), cfg.faultGameSplitDepth());
         assertEq(gameImpl.clockExtension().raw(), cfg.faultGameClockExtension());