// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {Script, console} from "forge-std/Script.sol"; import "../../../contracts/bridge/trustless/EnhancedSwapRouter.sol"; /** * @title DeployEnhancedSwapRouter * @notice Deployment script for EnhancedSwapRouter with multi-protocol support * @dev Deploys EnhancedSwapRouter with Uniswap V3, Curve, Dodoex, Balancer, and 1inch */ contract DeployEnhancedSwapRouter is Script { address constant PLACEHOLDER = 0x000000000000000000000000000000000000dEaD; // Ethereum Mainnet addresses address constant UNISWAP_V3_ROUTER = 0x68b3465833fb72A70ecDF485E0e4C7bD8665Fc45; address constant CURVE_3POOL = 0xbEbc44782C7dB0a1A60Cb6fe97d0b483032FF1C7; address constant DODOEX_ROUTER = 0xa356867fDCEa8e71AEaF87805808803806231FdC; address constant BALANCER_VAULT = 0xBA12222222228d8Ba445958a75a0704d566BF2C8; address constant ONEINCH_ROUTER = 0x1111111254EEB25477B68fb85Ed929f73A960582; address constant WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address constant USDT = 0xdAC17F958D2ee523a2206206994597C13D831ec7; address constant USDC = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; address constant DAI = 0x6B175474E89094C44Da98b954EedeAC495271d0F; // Chain 138 canonical token addresses address constant CHAIN138_WETH = 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2; address constant CHAIN138_USDT = 0x004b63A7B5b0E06f6bB6adb4a5F9f590BF3182D1; address constant CHAIN138_USDC = 0x71D6687F38b93CCad569Fa6352c876eea967201b; address constant CHAIN138_DAI_PLACEHOLDER = 0x6B175474E89094C44Da98b954EedeAC495271d0F; // Chain 138 live DODO pool map (2026-03-26) address constant CHAIN138_cUSDT = 0x93E66202A11B1772E55407B32B44e5Cd8eda7f22; address constant CHAIN138_cUSDC = 0xf22258f57794CC8E06237084b353Ab30fFfa640b; address constant CHAIN138_cEURT = 0xdf4b71c61E5912712C1Bdd451416B9aC26949d72; address constant CHAIN138_cXAUC = 0x290E52a8819A4fbD0714E517225429aA2B70EC6b; address constant CHAIN138_POOL_CUSDTCUSDC = 0xff8d3b8fDF7B112759F076B69f4271D4209C0849; address constant CHAIN138_POOL_CUSDTUSDT = 0x6fc60DEDc92a2047062294488539992710b99D71; address constant CHAIN138_POOL_CUSDCUSDC = 0x0309178Ae30302D83C76d6DD402a684ef3160eeC; address constant CHAIN138_POOL_CUSDT_XAU_PUBLIC = 0x1AA55E2001E5651349aFf5a63FD7a7ae44f0f1b0; address constant CHAIN138_POOL_CUSDC_XAU_PUBLIC = 0xEa9AC6357CaCB42a83b9082B870610363b177CbA; address constant CHAIN138_POOL_CEURT_XAU_PUBLIC = 0xba99bc1eAac164569d5aca96c806934dDaf970CF; function run() external { uint256 deployerPrivateKey = vm.envUint("PRIVATE_KEY"); address deployer = vm.addr(deployerPrivateKey); uint256 chainId = block.chainid; bool isMainnet = chainId == 1; bool isChain138 = chainId == 138; require(isMainnet || isChain138, "DeployEnhancedSwapRouter: supported chains are Ethereum Mainnet and Chain 138"); ( address uniswapV3Router, address curve3Pool, address dodoexRouter, address balancerVault, address oneInchRouter, address weth, address usdt, address usdc, address dai ) = _resolveAddresses(chainId); console.log("=== EnhancedSwapRouter Deployment ==="); console.log("Deployer:", deployer); console.log("Chain ID:", chainId); if (isChain138) { console.log("Mode: Chain 138 env-driven deployment"); console.log("Note: live DODO pools are stable/stable and stable/XAU."); console.log("Note: WETH->stable routing remains optional until real WETH routes are configured."); } vm.startBroadcast(deployerPrivateKey); console.log("\n--- Deploying EnhancedSwapRouter ---"); console.log("Uniswap V3 Router:", uniswapV3Router); console.log("Curve 3Pool:", curve3Pool); console.log("Dodoex Router:", dodoexRouter); console.log("Balancer Vault:", balancerVault); console.log("1inch Router:", oneInchRouter); console.log("WETH:", weth); console.log("USDT:", usdt); console.log("USDC:", usdc); console.log("DAI:", dai); EnhancedSwapRouter router = new EnhancedSwapRouter( uniswapV3Router, curve3Pool, dodoexRouter, balancerVault, oneInchRouter, weth, usdt, usdc, dai ); console.log("\nEnhancedSwapRouter deployed at:", address(router)); // Grant ROUTING_MANAGER_ROLE to deployer so setRoutingConfig can be called router.grantRole(router.ROUTING_MANAGER_ROLE(), deployer); // Configure default routing _configureDefaultRouting(router); if (isChain138) { _configureChain138InitialState(router, uniswapV3Router, curve3Pool, dodoexRouter, balancerVault, oneInchRouter); } vm.stopBroadcast(); console.log("\n=== Deployment Summary ==="); console.log("EnhancedSwapRouter:", address(router)); console.log("\n=== Export to .env ==="); console.log("export ENHANCED_SWAP_ROUTER=", vm.toString(address(router))); if (isChain138) { console.log("export ENHANCED_SWAP_ROUTER_CHAIN138=", vm.toString(address(router))); console.log("export ENHANCED_SWAP_ROUTER_ADDRESS=", vm.toString(address(router))); } } function _configureDefaultRouting(EnhancedSwapRouter router) internal { console.log("\n--- Configuring Default Routing ---"); // Small swaps (< $10k): Uniswap V3, Dodoex EnhancedSwapRouter.SwapProvider[] memory smallProviders = new EnhancedSwapRouter.SwapProvider[](2); smallProviders[0] = EnhancedSwapRouter.SwapProvider.UniswapV3; smallProviders[1] = EnhancedSwapRouter.SwapProvider.Dodoex; router.setRoutingConfig(0, smallProviders); console.log("Small swap routing configured"); // Medium swaps ($10k-$100k): Dodoex, Balancer, Uniswap V3 EnhancedSwapRouter.SwapProvider[] memory mediumProviders = new EnhancedSwapRouter.SwapProvider[](3); mediumProviders[0] = EnhancedSwapRouter.SwapProvider.Dodoex; mediumProviders[1] = EnhancedSwapRouter.SwapProvider.Balancer; mediumProviders[2] = EnhancedSwapRouter.SwapProvider.UniswapV3; router.setRoutingConfig(1, mediumProviders); console.log("Medium swap routing configured"); // Large swaps (> $100k): Dodoex, Curve, Balancer EnhancedSwapRouter.SwapProvider[] memory largeProviders = new EnhancedSwapRouter.SwapProvider[](3); largeProviders[0] = EnhancedSwapRouter.SwapProvider.Dodoex; largeProviders[1] = EnhancedSwapRouter.SwapProvider.Curve; largeProviders[2] = EnhancedSwapRouter.SwapProvider.Balancer; router.setRoutingConfig(2, largeProviders); console.log("Large swap routing configured"); // Note: Balancer pool IDs need to be configured separately // after identifying the actual pool addresses console.log("\nWARNING: Remember to configure Balancer pool IDs after deployment"); } function _configureChain138InitialState( EnhancedSwapRouter router, address uniswapV3Router, address curve3Pool, address dodoexRouter, address balancerVault, address oneInchRouter ) internal { console.log("\n--- Chain 138 Initial Configuration ---"); address dodoPmmProvider = vm.envOr("DODO_PMM_PROVIDER_ADDRESS", address(0)); if (dodoPmmProvider == address(0)) { dodoPmmProvider = vm.envOr("DODO_PMM_PROVIDER", address(0)); } _registerPair(router, CHAIN138_cUSDT, CHAIN138_cUSDC, CHAIN138_POOL_CUSDTCUSDC); _registerPair(router, CHAIN138_cUSDT, CHAIN138_USDT, CHAIN138_POOL_CUSDTUSDT); _registerPair(router, CHAIN138_cUSDC, CHAIN138_USDC, CHAIN138_POOL_CUSDCUSDC); _registerPair(router, CHAIN138_cUSDT, CHAIN138_cXAUC, CHAIN138_POOL_CUSDT_XAU_PUBLIC); _registerPair(router, CHAIN138_cUSDC, CHAIN138_cXAUC, CHAIN138_POOL_CUSDC_XAU_PUBLIC); _registerPair(router, CHAIN138_cEURT, CHAIN138_cXAUC, CHAIN138_POOL_CEURT_XAU_PUBLIC); if (dodoPmmProvider != address(0)) { router.setDodoLiquidityProvider(dodoPmmProvider); console.log("Configured DODO PMM provider:", dodoPmmProvider); } // Disable providers that are definitely not usable until explicitly configured on Chain 138. if (curve3Pool == PLACEHOLDER) { router.setProviderEnabled(EnhancedSwapRouter.SwapProvider.Curve, false); console.log("Disabled Curve provider (placeholder address)"); } if (balancerVault == PLACEHOLDER) { router.setProviderEnabled(EnhancedSwapRouter.SwapProvider.Balancer, false); console.log("Disabled Balancer provider (placeholder address)"); } if (oneInchRouter == PLACEHOLDER) { router.setProviderEnabled(EnhancedSwapRouter.SwapProvider.OneInch, false); console.log("Disabled 1inch provider (placeholder address)"); } if (uniswapV3Router == PLACEHOLDER) { router.setProviderEnabled(EnhancedSwapRouter.SwapProvider.UniswapV3, false); console.log("Disabled Uniswap V3 provider (placeholder address)"); } if (dodoexRouter == PLACEHOLDER && dodoPmmProvider == address(0)) { router.setProviderEnabled(EnhancedSwapRouter.SwapProvider.Dodoex, false); console.log("Disabled Dodoex provider (no router and no PMM provider configured)"); } else { console.log("Dodo pool mappings registered for current live Chain 138 pairs."); } console.log("WARNING: swapToStablecoin() still needs real WETH->stable routes to be useful on Chain 138."); console.log("WARNING: current Chain 138 DODO initialization is primarily for token-to-token pair mappings via swapTokenToToken()."); } function _registerPair( EnhancedSwapRouter router, address tokenA, address tokenB, address pool ) internal { router.setDodoPoolAddress(tokenA, tokenB, pool); router.setDodoPoolAddress(tokenB, tokenA, pool); console.log("Registered DODO pool:", pool); } function _resolveAddresses( uint256 chainId ) internal returns ( address uniswapV3Router, address curve3Pool, address dodoexRouter, address balancerVault, address oneInchRouter, address weth, address usdt, address usdc, address dai ) { if (chainId == 1) { uniswapV3Router = vm.envOr("UNISWAP_V3_ROUTER", UNISWAP_V3_ROUTER); curve3Pool = vm.envOr("CURVE_3POOL", CURVE_3POOL); dodoexRouter = vm.envOr("DODOEX_ROUTER", DODOEX_ROUTER); balancerVault = vm.envOr("BALANCER_VAULT", BALANCER_VAULT); oneInchRouter = vm.envOr("ONEINCH_ROUTER", ONEINCH_ROUTER); weth = vm.envOr("WETH", WETH); usdt = vm.envOr("USDT", USDT); usdc = vm.envOr("USDC", USDC); dai = vm.envOr("DAI", DAI); return (uniswapV3Router, curve3Pool, dodoexRouter, balancerVault, oneInchRouter, weth, usdt, usdc, dai); } // Chain 138: use canonical token defaults and env-driven protocol addresses. uniswapV3Router = vm.envOr("UNISWAP_V3_ROUTER", PLACEHOLDER); curve3Pool = vm.envOr("CURVE_3POOL", PLACEHOLDER); dodoexRouter = vm.envOr("DODOEX_ROUTER", PLACEHOLDER); balancerVault = vm.envOr("BALANCER_VAULT", PLACEHOLDER); oneInchRouter = vm.envOr("ONEINCH_ROUTER", PLACEHOLDER); weth = vm.envOr("WETH", CHAIN138_WETH); usdt = vm.envOr("OFFICIAL_USDT_ADDRESS", CHAIN138_USDT); usdc = vm.envOr("OFFICIAL_USDC_ADDRESS", CHAIN138_USDC); dai = vm.envOr("DAI", CHAIN138_DAI_PLACEHOLDER); } }