// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {Script, console} from "forge-std/Script.sol"; import "../../../contracts/bridge/trustless/Lockbox138.sol"; import "../../../contracts/bridge/trustless/BondManager.sol"; import "../../../contracts/bridge/trustless/ChallengeManager.sol"; import "../../../contracts/bridge/trustless/LiquidityPoolETH.sol"; import "../../../contracts/bridge/trustless/InboxETH.sol"; import "../../../contracts/bridge/trustless/SwapRouter.sol"; import "../../../contracts/bridge/trustless/BridgeSwapCoordinator.sol"; /** * @title DeployTrustlessBridge * @notice Deployment script for trustless bridge system * @dev Deploys contracts in correct dependency order */ contract DeployTrustlessBridge is Script { // Configuration parameters (defaults, can be overridden via environment) uint256 constant DEFAULT_BOND_MULTIPLIER = 11000; // 110% in basis points uint256 constant DEFAULT_MIN_BOND = 1 ether; uint256 constant DEFAULT_CHALLENGE_WINDOW = 30 minutes; uint256 constant DEFAULT_LP_FEE_BPS = 5; // 0.05% uint256 constant DEFAULT_MIN_LIQUIDITY_RATIO_BPS = 11000; // 110% // Ethereum Mainnet addresses address constant UNISWAP_V3_ROUTER = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45; address constant CURVE_3POOL = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7; address constant ONEINCH_ROUTER = 0x1111111254EEB25477B68fb85Ed929f73A960582; address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; struct DeploymentAddresses { // ChainID 138 address lockbox138; // Ethereum Mainnet address bondManager; address challengeManager; address liquidityPool; address inbox; address swapRouter; address coordinator; } function run() external { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); address deployer = vm.addr(deployerPrivateKey); console.log("=== Trustless Bridge Deployment ==="); console.log("Deployer:", deployer); console.log("Chain ID:", block.chainid); // Detect which chain we're on (138, 1, or L2 with TRUSTLESS_WETH_ADDRESS) bool isChain138 = block.chainid == 138; bool isEthereum = block.chainid == 1; address l2Weth = vm.envOr("TRUSTLESS_WETH_ADDRESS", address(0)); bool isL2 = !isChain138 && !isEthereum && l2Weth != address(0); if (!isChain138 && !isEthereum && !isL2) { revert("DeployTrustlessBridge: unsupported chain (set TRUSTLESS_WETH_ADDRESS for L2)"); } vm.startBroadcast(deployerPrivateKey); DeploymentAddresses memory addresses; if (isChain138) { console.log("\n--- Deploying on ChainID 138 ---"); addresses.lockbox138 = _deployLockbox138(); } if (isEthereum) { console.log("\n--- Deploying on Ethereum Mainnet ---"); // Get configuration from environment or use defaults uint256 bondMultiplier = vm.envOr("BOND_MULTIPLIER_BPS", DEFAULT_BOND_MULTIPLIER); uint256 minBond = vm.envOr("MIN_BOND", DEFAULT_MIN_BOND); uint256 challengeWindow = vm.envOr("CHALLENGE_WINDOW_SECONDS", DEFAULT_CHALLENGE_WINDOW); uint256 lpFeeBps = vm.envOr("LP_FEE_BPS", DEFAULT_LP_FEE_BPS); uint256 minLiquidityRatioBps = vm.envOr("MIN_LIQUIDITY_RATIO_BPS", DEFAULT_MIN_LIQUIDITY_RATIO_BPS); addresses.bondManager = _deployBondManager(bondMultiplier, minBond); addresses.challengeManager = _deployChallengeManager(addresses.bondManager, challengeWindow); addresses.liquidityPool = _deployLiquidityPool(WETH, lpFeeBps, minLiquidityRatioBps); addresses.inbox = _deployInboxETH( addresses.bondManager, addresses.challengeManager, addresses.liquidityPool ); addresses.swapRouter = _deploySwapRouter(); addresses.coordinator = _deployCoordinator( addresses.inbox, addresses.liquidityPool, addresses.swapRouter, addresses.challengeManager ); // Authorize coordinator to release funds from liquidity pool _authorizeCoordinator(addresses.liquidityPool, addresses.coordinator); _authorizeInbox(addresses.liquidityPool, addresses.inbox); } if (isL2) { console.log("\n--- Deploying Trustless stack on L2 (chain id ", block.chainid, ") ---"); uint256 bondMultiplier = vm.envOr("BOND_MULTIPLIER_BPS", DEFAULT_BOND_MULTIPLIER); uint256 minBond = vm.envOr("MIN_BOND", DEFAULT_MIN_BOND); uint256 challengeWindow = vm.envOr("CHALLENGE_WINDOW_SECONDS", DEFAULT_CHALLENGE_WINDOW); uint256 lpFeeBps = vm.envOr("LP_FEE_BPS", DEFAULT_LP_FEE_BPS); uint256 minLiquidityRatioBps = vm.envOr("MIN_LIQUIDITY_RATIO_BPS", DEFAULT_MIN_LIQUIDITY_RATIO_BPS); addresses.bondManager = _deployBondManager(bondMultiplier, minBond); addresses.challengeManager = _deployChallengeManager(addresses.bondManager, challengeWindow); addresses.liquidityPool = _deployLiquidityPool(l2Weth, lpFeeBps, minLiquidityRatioBps); addresses.inbox = _deployInboxETH( addresses.bondManager, addresses.challengeManager, addresses.liquidityPool ); _authorizeInbox(addresses.liquidityPool, addresses.inbox); string memory deployLb = vm.envOr("TRUSTLESS_DEPLOY_LOCKBOX", string("0")); if (keccak256(bytes(deployLb)) == keccak256("1") || keccak256(bytes(deployLb)) == keccak256("true")) { addresses.lockbox138 = _deployLockbox138(); } } vm.stopBroadcast(); // Print deployment summary console.log("\n=== Deployment Summary ==="); if (isChain138) { console.log("Lockbox138:", addresses.lockbox138); } if (isEthereum) { console.log("BondManager:", addresses.bondManager); console.log("ChallengeManager:", addresses.challengeManager); console.log("LiquidityPoolETH:", addresses.liquidityPool); console.log("InboxETH:", addresses.inbox); console.log("SwapRouter:", addresses.swapRouter); console.log("BridgeSwapCoordinator:", addresses.coordinator); } if (isL2) { console.log("BondManager:", addresses.bondManager); console.log("ChallengeManager:", addresses.challengeManager); console.log("LiquidityPoolETH:", addresses.liquidityPool); console.log("InboxETH:", addresses.inbox); if (addresses.lockbox138 != address(0)) console.log("Lockbox:", addresses.lockbox138); } } function _deployLockbox138() internal returns (address) { console.log("Deploying Lockbox138..."); Lockbox138 lockbox = new Lockbox138(); console.log("Lockbox138 deployed at:", address(lockbox)); return address(lockbox); } function _deployBondManager(uint256 bondMultiplier, uint256 minBond) internal returns (address) { console.log("Deploying BondManager..."); console.log(" Bond Multiplier (bps):", bondMultiplier); console.log(" Min Bond:", minBond); BondManager bondManager = new BondManager(bondMultiplier, minBond); console.log("BondManager deployed at:", address(bondManager)); return address(bondManager); } function _deployChallengeManager(address bondManager, uint256 challengeWindow) internal returns (address) { console.log("Deploying ChallengeManager..."); console.log(" BondManager:", bondManager); console.log(" Challenge Window (seconds):", challengeWindow); ChallengeManager challengeManager = new ChallengeManager(bondManager, challengeWindow); console.log("ChallengeManager deployed at:", address(challengeManager)); return address(challengeManager); } function _deployLiquidityPool( address weth, uint256 lpFeeBps, uint256 minLiquidityRatioBps ) internal returns (address) { console.log("Deploying LiquidityPoolETH..."); console.log(" WETH:", weth); console.log(" LP Fee (bps):", lpFeeBps); console.log(" Min Liquidity Ratio (bps):", minLiquidityRatioBps); LiquidityPoolETH pool = new LiquidityPoolETH(weth, lpFeeBps, minLiquidityRatioBps); console.log("LiquidityPoolETH deployed at:", address(pool)); return address(pool); } function _deployInboxETH( address bondManager, address challengeManager, address liquidityPool ) internal returns (address) { console.log("Deploying InboxETH..."); console.log(" BondManager:", bondManager); console.log(" ChallengeManager:", challengeManager); console.log(" LiquidityPool:", liquidityPool); InboxETH inbox = new InboxETH(bondManager, challengeManager, liquidityPool); console.log("InboxETH deployed at:", address(inbox)); return address(inbox); } function _deploySwapRouter() internal returns (address) { console.log("Deploying SwapRouter..."); console.log(" Uniswap V3 Router:", UNISWAP_V3_ROUTER); console.log(" Curve 3Pool:", CURVE_3POOL); console.log(" 1inch Router:", ONEINCH_ROUTER); SwapRouter router = new SwapRouter( UNISWAP_V3_ROUTER, CURVE_3POOL, ONEINCH_ROUTER, WETH, USDT, USDC, DAI ); console.log("SwapRouter deployed at:", address(router)); return address(router); } function _deployCoordinator( address inbox, address liquidityPool, address swapRouter, address challengeManager ) internal returns (address) { console.log("Deploying BridgeSwapCoordinator..."); console.log(" Inbox:", inbox); console.log(" LiquidityPool:", liquidityPool); console.log(" SwapRouter:", swapRouter); console.log(" ChallengeManager:", challengeManager); BridgeSwapCoordinator coordinator = new BridgeSwapCoordinator( inbox, liquidityPool, swapRouter, challengeManager ); console.log("BridgeSwapCoordinator deployed at:", address(coordinator)); return address(coordinator); } function _authorizeCoordinator(address liquidityPool, address coordinator) internal { console.log("Authorizing coordinator in liquidity pool..."); LiquidityPoolETH(payable(liquidityPool)).authorizeRelease(coordinator); console.log("Coordinator authorized"); } function _authorizeInbox(address liquidityPool, address inbox) internal { console.log("Authorizing inbox in liquidity pool..."); LiquidityPoolETH(payable(liquidityPool)).authorizeRelease(inbox); console.log("Inbox authorized"); } }