- Resolve stash: merge load_deployment_env path with secure-secrets and CR/LF RPC strip - create-pmm-full-mesh-chain138.sh delegates to sync-chain138-pmm-pools-from-json.sh - env.additions.example: canonical PMM pool defaults (cUSDT/USDT per crosscheck) - Include Chain138 scripts, official mirror deploy scaffolding, and prior staged changes Made-with: Cursor
226 lines
8.2 KiB
Solidity
226 lines
8.2 KiB
Solidity
// SPDX-License-Identifier: MIT
|
|
pragma solidity ^0.8.19;
|
|
|
|
import {Test} from "forge-std/Test.sol";
|
|
import "../../../contracts/bridge/trustless/EnhancedSwapRouter.sol";
|
|
import "../../../contracts/bridge/trustless/LiquidityPoolETH.sol";
|
|
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
|
|
|
|
contract MockERC20 is ERC20 {
|
|
constructor(string memory name, string memory symbol) ERC20(name, symbol) {
|
|
_mint(msg.sender, 1000000 ether);
|
|
}
|
|
}
|
|
|
|
contract MockLiquidityProvider {
|
|
mapping(address => mapping(address => bool)) public supported;
|
|
mapping(address => mapping(address => uint256)) public quotes;
|
|
|
|
function setSupport(address tokenIn, address tokenOut, bool isSupported) external {
|
|
supported[tokenIn][tokenOut] = isSupported;
|
|
}
|
|
|
|
function setQuote(address tokenIn, address tokenOut, uint256 amountOut) external {
|
|
quotes[tokenIn][tokenOut] = amountOut;
|
|
}
|
|
|
|
function getQuote(
|
|
address tokenIn,
|
|
address tokenOut,
|
|
uint256
|
|
) external view returns (uint256 amountOut, uint256 slippageBps) {
|
|
if (!supported[tokenIn][tokenOut]) {
|
|
return (0, 10000);
|
|
}
|
|
return (quotes[tokenIn][tokenOut], 30);
|
|
}
|
|
|
|
function executeSwap(
|
|
address tokenIn,
|
|
address tokenOut,
|
|
uint256 amountIn,
|
|
uint256
|
|
) external returns (uint256 amountOut) {
|
|
require(supported[tokenIn][tokenOut], "unsupported");
|
|
amountOut = quotes[tokenIn][tokenOut];
|
|
ERC20(tokenIn).transferFrom(msg.sender, address(this), amountIn);
|
|
ERC20(tokenOut).transfer(msg.sender, amountOut);
|
|
}
|
|
|
|
function supportsTokenPair(address tokenIn, address tokenOut) external view returns (bool) {
|
|
return supported[tokenIn][tokenOut];
|
|
}
|
|
|
|
function providerName() external pure returns (string memory) {
|
|
return "Mock";
|
|
}
|
|
|
|
function estimateGas(address, address, uint256) external pure returns (uint256) {
|
|
return 150000;
|
|
}
|
|
}
|
|
|
|
contract EnhancedSwapRouterTest is Test {
|
|
EnhancedSwapRouter public router;
|
|
LiquidityPoolETH public liquidityPool;
|
|
MockLiquidityProvider public liquidityProvider;
|
|
|
|
MockERC20 public weth;
|
|
MockERC20 public usdt;
|
|
MockERC20 public usdc;
|
|
MockERC20 public dai;
|
|
|
|
address public deployer = address(0xDE0001);
|
|
address public user = address(0x1111);
|
|
|
|
// Mock protocol addresses
|
|
address public uniswapV3Router = address(0x1111111111111111111111111111111111111111);
|
|
address public curve3Pool = address(0x2222222222222222222222222222222222222222);
|
|
address public dodoexRouter = address(0x3333333333333333333333333333333333333333);
|
|
address public balancerVault = address(0x4444444444444444444444444444444444444444);
|
|
address public oneInchRouter = address(0x5555555555555555555555555555555555555555);
|
|
|
|
function setUp() public {
|
|
vm.startPrank(deployer);
|
|
|
|
// Deploy mock tokens
|
|
weth = new MockERC20("Wrapped Ether", "WETH");
|
|
usdt = new MockERC20("Tether USD", "USDT");
|
|
usdc = new MockERC20("USD Coin", "USDC");
|
|
dai = new MockERC20("Dai Stablecoin", "DAI");
|
|
liquidityProvider = new MockLiquidityProvider();
|
|
|
|
// Deploy liquidity pool
|
|
liquidityPool = new LiquidityPoolETH(address(weth), 5, 11000);
|
|
|
|
// Deploy enhanced swap router
|
|
router = new EnhancedSwapRouter(
|
|
uniswapV3Router,
|
|
curve3Pool,
|
|
dodoexRouter,
|
|
balancerVault,
|
|
oneInchRouter,
|
|
address(weth),
|
|
address(usdt),
|
|
address(usdc),
|
|
address(dai)
|
|
);
|
|
|
|
// Grant ROUTING_MANAGER_ROLE to deployer for tests
|
|
router.grantRole(router.ROUTING_MANAGER_ROLE(), deployer);
|
|
|
|
// Fund user
|
|
vm.deal(user, 100 ether);
|
|
|
|
vm.stopPrank();
|
|
}
|
|
|
|
function testInitialization() public {
|
|
assertEq(address(router.weth()), address(weth));
|
|
assertEq(address(router.usdt()), address(usdt));
|
|
assertTrue(router.providerEnabled(EnhancedSwapRouter.SwapProvider.UniswapV3));
|
|
assertTrue(router.providerEnabled(EnhancedSwapRouter.SwapProvider.Dodoex));
|
|
}
|
|
|
|
function testSetProviderEnabled() public {
|
|
// Deployer already has ROUTING_MANAGER_ROLE from setUp
|
|
vm.prank(deployer);
|
|
router.setProviderEnabled(EnhancedSwapRouter.SwapProvider.UniswapV3, false);
|
|
|
|
assertFalse(router.providerEnabled(EnhancedSwapRouter.SwapProvider.UniswapV3));
|
|
|
|
// Re-enable for other tests
|
|
vm.prank(deployer);
|
|
router.setProviderEnabled(EnhancedSwapRouter.SwapProvider.UniswapV3, true);
|
|
|
|
assertTrue(router.providerEnabled(EnhancedSwapRouter.SwapProvider.UniswapV3));
|
|
}
|
|
|
|
function testSetRoutingConfig() public {
|
|
// Deployer already has ROUTING_MANAGER_ROLE from setUp
|
|
EnhancedSwapRouter.SwapProvider[] memory providers = new EnhancedSwapRouter.SwapProvider[](2);
|
|
providers[0] = EnhancedSwapRouter.SwapProvider.Dodoex;
|
|
providers[1] = EnhancedSwapRouter.SwapProvider.Balancer;
|
|
|
|
vm.prank(deployer);
|
|
router.setRoutingConfig(0, providers); // Small swaps
|
|
|
|
// Verify config was set (would need getter function)
|
|
// For now, just verify no revert
|
|
assertTrue(true);
|
|
}
|
|
|
|
function testSetBalancerPoolId() public {
|
|
// Deployer already has ROUTING_MANAGER_ROLE from setUp
|
|
bytes32 poolId = keccak256("test-pool");
|
|
|
|
vm.prank(deployer);
|
|
router.setBalancerPoolId(address(weth), address(usdt), poolId);
|
|
|
|
assertEq(router.balancerPoolIds(address(weth), address(usdt)), poolId);
|
|
}
|
|
|
|
function testGetQuotes() public view {
|
|
// This would require actual protocol integration
|
|
// For now, just verify function exists
|
|
(EnhancedSwapRouter.SwapProvider[] memory providers, uint256[] memory amounts) =
|
|
router.getQuotes(address(usdt), 1 ether);
|
|
|
|
// In production, would verify quotes are returned
|
|
assertTrue(providers.length >= 0);
|
|
}
|
|
|
|
function testSetDodoPoolAddress() public {
|
|
address mockPool = address(0xDD00);
|
|
vm.prank(deployer);
|
|
router.setDodoPoolAddress(address(weth), address(usdt), mockPool);
|
|
assertEq(router.dodoPoolAddresses(address(weth), address(usdt)), mockPool);
|
|
vm.prank(deployer);
|
|
router.setDodoPoolAddress(address(usdt), address(weth), mockPool);
|
|
assertEq(router.dodoPoolAddresses(address(usdt), address(weth)), mockPool);
|
|
}
|
|
|
|
function testSwapTokenToTokenRevertsWhenPoolNotSet() public {
|
|
vm.prank(user);
|
|
weth.approve(address(router), 1 ether);
|
|
vm.expectRevert(EnhancedSwapRouter.DodoRouteNotConfigured.selector);
|
|
router.swapTokenToToken(address(weth), address(usdt), 1 ether, 0);
|
|
}
|
|
|
|
function testSetDodoLiquidityProvider() public {
|
|
vm.prank(deployer);
|
|
router.setDodoLiquidityProvider(address(liquidityProvider));
|
|
assertEq(router.dodoLiquidityProvider(), address(liquidityProvider));
|
|
}
|
|
|
|
function testGetQuotesUsesDodoLiquidityProviderWhenRouteSupported() public {
|
|
vm.startPrank(deployer);
|
|
router.setDodoLiquidityProvider(address(liquidityProvider));
|
|
router.setProviderEnabled(EnhancedSwapRouter.SwapProvider.UniswapV3, false);
|
|
router.setProviderEnabled(EnhancedSwapRouter.SwapProvider.Balancer, false);
|
|
vm.stopPrank();
|
|
|
|
liquidityProvider.setSupport(address(weth), address(usdt), true);
|
|
liquidityProvider.setQuote(address(weth), address(usdt), 1234);
|
|
|
|
(EnhancedSwapRouter.SwapProvider[] memory providers, uint256[] memory amounts) =
|
|
router.getQuotes(address(usdt), 1 ether);
|
|
|
|
assertEq(providers.length, 1);
|
|
assertEq(uint256(providers[0]), uint256(EnhancedSwapRouter.SwapProvider.Dodoex));
|
|
assertEq(amounts[0], 1234);
|
|
}
|
|
|
|
function testSwapTokenToTokenRevertsWhenProviderRouteMissing() public {
|
|
address mockPool = address(0xDD00);
|
|
vm.startPrank(deployer);
|
|
router.setDodoPoolAddress(address(weth), address(usdt), mockPool);
|
|
router.setDodoLiquidityProvider(address(liquidityProvider));
|
|
vm.stopPrank();
|
|
|
|
vm.prank(user);
|
|
vm.expectRevert(EnhancedSwapRouter.DodoRouteNotConfigured.selector);
|
|
router.swapTokenToToken(address(weth), address(usdt), 1 ether, 0);
|
|
}
|
|
}
|