// SPDX-License-Identifier: MIT pragma solidity ^0.8.20; import "forge-std/Script.sol"; import {CREATE2Factory} from "../../contracts/utils/CREATE2Factory.sol"; import {MirrorRegistry} from "../../contracts/mirror/MirrorRegistry.sol"; import {UniversalCCIPBridge} from "../../contracts/bridge/UniversalCCIPBridge.sol"; import {UniversalAssetRegistry} from "../../contracts/registry/UniversalAssetRegistry.sol"; import {AlltraAdapter} from "../../contracts/bridge/adapters/evm/AlltraAdapter.sol"; import {ERC1967Proxy} from "@openzeppelin/contracts/proxy/ERC1967/ERC1967Proxy.sol"; /** * @title DeployDeterministicCore * @notice Deploy MirrorRegistry, UniversalCCIPBridge (proxy), UniversalAssetRegistry, AlltraAdapter via CREATE2 with fixed salts. * @dev Use identical ADMIN and (where applicable) ASSET_REGISTRY per chain so addresses match. Call setCCIPRouter(router) on bridge after deploy on each chain. * See docs/runbooks/MULTI_CHAIN_EXECUTION_DETERMINISTIC_DEPLOYMENT.md * Refactored to avoid Yul stack-too-deep: single struct + internal deployAll to minimize run() stack. */ contract DeployDeterministicCore is Script { uint256 constant SALT_MIRROR_REGISTRY = uint256(keccak256("MirrorRegistry")); uint256 constant SALT_UNIVERSAL_ASSET_REGISTRY_IMPL = uint256(keccak256("UniversalAssetRegistry")); uint256 constant SALT_UNIVERSAL_ASSET_REGISTRY_PROXY = uint256(keccak256("UniversalAssetRegistry.Proxy")); uint256 constant SALT_CCIP_BRIDGE_IMPL = uint256(keccak256("UniversalCCIPBridge")); uint256 constant SALT_CCIP_BRIDGE_PROXY = uint256(keccak256("UniversalCCIPBridge.Proxy")); uint256 constant SALT_ALLTRA_ADAPTER = uint256(keccak256("AlltraAdapter")); struct DeployResult { address factory; address registry; address bridgeProxy; address mirror; address adapter; } function run() external { uint256 pk = vm.envUint("PRIVATE_KEY"); address admin = vm.envOr("ADMIN", vm.addr(pk)); vm.startBroadcast(pk); DeployResult memory r = _deployAll(admin); vm.stopBroadcast(); console.log("CREATE2Factory:", r.factory); console.log("UniversalAssetRegistry:", r.registry); console.log("UniversalCCIPBridge proxy:", r.bridgeProxy); console.log("MirrorRegistry:", r.mirror); console.log("AlltraAdapter:", r.adapter); console.log("\n--- Deterministic deployment summary ---"); console.log("Call UniversalCCIPBridge.setCCIPRouter(router) on each chain after deploy."); } function _deployAll(address admin) internal returns (DeployResult memory r) { CREATE2Factory factory = new CREATE2Factory(); r.factory = address(factory); address registryImpl = factory.deploy(type(UniversalAssetRegistry).creationCode, SALT_UNIVERSAL_ASSET_REGISTRY_IMPL); bytes memory registryInitData = abi.encodeCall(UniversalAssetRegistry.initialize, (admin)); bytes memory registryProxyBytecode = abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(registryImpl, registryInitData)); r.registry = factory.deploy(registryProxyBytecode, SALT_UNIVERSAL_ASSET_REGISTRY_PROXY); address impl = factory.deploy(type(UniversalCCIPBridge).creationCode, SALT_CCIP_BRIDGE_IMPL); address ccipRouter = vm.envOr("CCIP_ROUTER", address(0)); bytes memory initData = abi.encodeCall(UniversalCCIPBridge.initialize, (r.registry, ccipRouter, admin)); bytes memory proxyBytecode = abi.encodePacked(type(ERC1967Proxy).creationCode, abi.encode(impl, initData)); r.bridgeProxy = factory.deploy(proxyBytecode, SALT_CCIP_BRIDGE_PROXY); r.mirror = factory.deploy( abi.encodePacked(type(MirrorRegistry).creationCode, abi.encode(admin)), SALT_MIRROR_REGISTRY ); r.adapter = factory.deploy( abi.encodePacked(type(AlltraAdapter).creationCode, abi.encode(admin, r.bridgeProxy)), SALT_ALLTRA_ADAPTER ); } }