From f92a391ea610ac845d2a74084a40261a91f8a20c Mon Sep 17 00:00:00 2001 From: parsaba Date: Fri, 22 Aug 2025 11:05:53 +0330 Subject: [PATCH] Initial commit for LSR-LTM integration --- remappings.txt | 8 +- src/core/LiquidToken.sol | 2 +- src/core/LiquidTokenManager.sol | 2 +- src/core/RewardsManager.sol | 2 +- src/core/StakerNode.sol | 2 +- src/core/StakerNodeCoordinator.sol | 2 +- src/core/WithdrawalManager.sol | 2 +- src/interfaces/ILiquidToken.sol | 2 +- src/interfaces/ILiquidTokenManager.sol | 2 +- src/interfaces/IRewardsManager.sol | 2 +- src/interfaces/IStakerNode.sol | 2 +- src/interfaces/IStakerNodeCoordinator.sol | 2 +- src/interfaces/IWithdrawalManager.sol | 2 +- test/LTMLSRIntegrationtest.t.sol | 332 +++------------------- 14 files changed, 64 insertions(+), 300 deletions(-) diff --git a/remappings.txt b/remappings.txt index e378162c..382e6942 100644 --- a/remappings.txt +++ b/remappings.txt @@ -6,6 +6,8 @@ lib/eigenlayer-contracts/=lib/eigenlayer-contracts/ @openzeppelin/contracts/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/contracts/ @openzeppelin-upgradeable/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/ @openzeppelin-upgradeable/contracts/=lib/eigenlayer-contracts/lib/openzeppelin-contracts-upgradeable-v4.9.0/contracts/ -@openzeppelin/contracts/proxy/transparent/TransparentUpgradeableProxy.sol=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/contracts/proxy/transparent/TransparentUpgradeableProxy.sol -@openzeppelin/contracts/proxy/beacon/IBeacon.sol=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/contracts/proxy/beacon/IBeacon.sol -@chainlink/contracts/src/interfaces/feeds/=lib/foundry-chainlink-toolkit/src/interfaces/feeds/ \ No newline at end of file +@chainlink/contracts/src/interfaces/feeds/=lib/foundry-chainlink-toolkit/src/interfaces/feeds/ +@lsr/=lsr-contracts/ +lsr-contracts/=lsr-contracts/ +@openzeppelin/contracts/utils/ReentrancyGuard.sol=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/contracts/security/ReentrancyGuard.sol +@openzeppelin/contracts/utils/Pausable.sol=lib/eigenlayer-contracts/lib/openzeppelin-contracts-v4.9.0/contracts/security/Pausable.sol \ No newline at end of file diff --git a/src/core/LiquidToken.sol b/src/core/LiquidToken.sol index 2e0aa9a1..a48aa6fb 100644 --- a/src/core/LiquidToken.sol +++ b/src/core/LiquidToken.sol @@ -424,4 +424,4 @@ contract LiquidToken is function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) { _unpause(); } -} +} \ No newline at end of file diff --git a/src/core/LiquidTokenManager.sol b/src/core/LiquidTokenManager.sol index 3844da6b..564b4df5 100644 --- a/src/core/LiquidTokenManager.sol +++ b/src/core/LiquidTokenManager.sol @@ -1388,4 +1388,4 @@ contract LiquidTokenManager is return strategy.underlyingToSharesView(amount); } -} +} \ No newline at end of file diff --git a/src/core/RewardsManager.sol b/src/core/RewardsManager.sol index eba3bf94..8471c4e3 100644 --- a/src/core/RewardsManager.sol +++ b/src/core/RewardsManager.sol @@ -290,4 +290,4 @@ contract RewardsManager is function _balanceAsset(IERC20 asset) internal view returns (uint256) { return unsupportedAssetBalances[address(asset)]; } -} +} \ No newline at end of file diff --git a/src/core/StakerNode.sol b/src/core/StakerNode.sol index f37ac456..be1d0514 100644 --- a/src/core/StakerNode.sol +++ b/src/core/StakerNode.sol @@ -247,4 +247,4 @@ contract StakerNode is IStakerNode, Initializable, ReentrancyGuardUpgradeable { } _; } -} +} \ No newline at end of file diff --git a/src/core/StakerNodeCoordinator.sol b/src/core/StakerNodeCoordinator.sol index 7c4e241f..de91fa69 100644 --- a/src/core/StakerNodeCoordinator.sol +++ b/src/core/StakerNodeCoordinator.sol @@ -264,4 +264,4 @@ contract StakerNodeCoordinator is IStakerNodeCoordinator, AccessControlUpgradeab } _; } -} +} \ No newline at end of file diff --git a/src/core/WithdrawalManager.sol b/src/core/WithdrawalManager.sol index 9cfdb90a..ef555b48 100644 --- a/src/core/WithdrawalManager.sol +++ b/src/core/WithdrawalManager.sol @@ -432,4 +432,4 @@ contract WithdrawalManager is IWithdrawalManager, Initializable, AccessControlUp return redemption; } -} +} \ No newline at end of file diff --git a/src/interfaces/ILiquidToken.sol b/src/interfaces/ILiquidToken.sol index 9e71db49..49eb76b0 100644 --- a/src/interfaces/ILiquidToken.sol +++ b/src/interfaces/ILiquidToken.sol @@ -184,4 +184,4 @@ interface ILiquidToken { /// @notice Unpauses the contract function unpause() external; -} +} \ No newline at end of file diff --git a/src/interfaces/ILiquidTokenManager.sol b/src/interfaces/ILiquidTokenManager.sol index 244edf70..e06e5a03 100644 --- a/src/interfaces/ILiquidTokenManager.sol +++ b/src/interfaces/ILiquidTokenManager.sol @@ -527,4 +527,4 @@ interface ILiquidTokenManager { /// @notice Returns the LSTSwapRouter contract /// @return The ILSTSwapRouter interface function lstSwapRouter() external view returns (ILSTSwapRouter); -} +} \ No newline at end of file diff --git a/src/interfaces/IRewardsManager.sol b/src/interfaces/IRewardsManager.sol index 82ebac59..a329a54d 100644 --- a/src/interfaces/IRewardsManager.sol +++ b/src/interfaces/IRewardsManager.sol @@ -84,4 +84,4 @@ interface IRewardsManager { /// @param assetList The list of assets to get balances for /// @return An array of asset balances function balanceAssets(IERC20[] calldata assetList) external view returns (uint256[] memory); -} +} \ No newline at end of file diff --git a/src/interfaces/IStakerNode.sol b/src/interfaces/IStakerNode.sol index d15b7254..56cf79d6 100644 --- a/src/interfaces/IStakerNode.sol +++ b/src/interfaces/IStakerNode.sol @@ -134,4 +134,4 @@ interface IStakerNode { /// Returns the address of the operator the node is delegate to /// @return The address of the delegated operator or zero address if not delegated function getOperatorDelegation() external view returns (address); -} +} \ No newline at end of file diff --git a/src/interfaces/IStakerNodeCoordinator.sol b/src/interfaces/IStakerNodeCoordinator.sol index a97075e8..3c0635b5 100644 --- a/src/interfaces/IStakerNodeCoordinator.sol +++ b/src/interfaces/IStakerNodeCoordinator.sol @@ -172,4 +172,4 @@ interface IStakerNodeCoordinator { /// @notice Gets the maximum number of nodes allowed /// @return The maximum number of nodes function maxNodes() external view returns (uint256); -} +} \ No newline at end of file diff --git a/src/interfaces/IWithdrawalManager.sol b/src/interfaces/IWithdrawalManager.sol index 350575f6..313a2591 100644 --- a/src/interfaces/IWithdrawalManager.sol +++ b/src/interfaces/IWithdrawalManager.sol @@ -244,4 +244,4 @@ interface IWithdrawalManager { /// @notice Returns all redemption details for a given redemption ID /// @param redemptionId The ID of the redemption function getRedemption(bytes32 redemptionId) external view returns (ILiquidTokenManager.Redemption memory); -} +} \ No newline at end of file diff --git a/test/LTMLSRIntegrationtest.t.sol b/test/LTMLSRIntegrationtest.t.sol index c30a5178..6471a8d5 100644 --- a/test/LTMLSRIntegrationtest.t.sol +++ b/test/LTMLSRIntegrationtest.t.sol @@ -4,14 +4,15 @@ pragma solidity ^0.8.19; import "forge-std/Test.sol"; import "forge-std/console.sol"; import "@openzeppelin/contracts/token/ERC20/IERC20.sol"; +import "@openzeppelin/contracts/utils/Strings.sol"; // Import contracts -import "./mocks/MockLSR.sol"; +import "@lsr/src/LSTSwapRouter.sol"; import "./mocks/MockLiquidTokenManager.sol"; contract LTMLSRIntegrationTest is Test { // Contracts - MockLSR public LSR; + LSTSwapRouter public LSR; MockLiquidTokenManager public ltm; // Mainnet addresses @@ -58,11 +59,11 @@ contract LTMLSRIntegrationTest is Test { // Initialize LSR _initializeLSR(); - // Configure essential routes for auto-routing tests - commented out for T2 integration - // _configureMinimalRoutes(); + // Configure essential routes for auto-routing tests + _configureMinimalRoutes(); - // Get test assets - commented out for T2 integration - // _getTestAssets(); + // Get test assets + _getTestAssets(); console.log("=== SETUP COMPLETE ===\n"); } @@ -73,7 +74,16 @@ contract LTMLSRIntegrationTest is Test { bytes32 passwordHash = keccak256(abi.encode(PASSWORD, predictedLSRAddress)); // Deploy LSR - LSR = new MockLSR(); + LSR = new LSTSwapRouter( + WETH, + UNISWAP_V3_ROUTER, + UNISWAP_V3_QUOTER, + FRXETH_MINTER, + address(this), + passwordHash, + address(this), + false + ); // Deploy Mock LTM ltm = new MockLiquidTokenManager(); @@ -93,7 +103,7 @@ contract LTMLSRIntegrationTest is Test { }); ltm.initialize(ltmInit); - // LSR.grantOperatorRole(address(ltm)); // Not needed for mock + LSR.grantOperatorRole(address(ltm)); } function _initializeLSR() internal { @@ -108,11 +118,10 @@ contract LTMLSRIntegrationTest is Test { tokens[6] = WBTC; tokens[7] = UNIBTC; - // AssetType not needed for LAT integration testing - // LSTSwapRouter.AssetType[] memory types = new LSTSwapRouter.AssetType[](8); - // for (uint i = 0; i < 6; i++) types[i] = LSTSwapRouter.AssetType.ETH_LST; - // types[6] = LSTSwapRouter.AssetType.BTC_WRAPPED; - // types[7] = LSTSwapRouter.AssetType.BTC_WRAPPED; + LSTSwapRouter.AssetType[] memory types = new LSTSwapRouter.AssetType[](8); + for (uint i = 0; i < 6; i++) types[i] = LSTSwapRouter.AssetType.ETH_LST; + types[6] = LSTSwapRouter.AssetType.BTC_WRAPPED; + types[7] = LSTSwapRouter.AssetType.BTC_WRAPPED; uint8[] memory decimals = new uint8[](8); for (uint i = 0; i < 6; i++) decimals[i] = 18; @@ -130,37 +139,33 @@ contract LTMLSRIntegrationTest is Test { uint256[] memory tokenCounts = new uint256[](5); for (uint i = 0; i < 5; i++) tokenCounts[i] = 2; - // CurveInterface not needed for LAT integration testing - // LSTSwapRouter.CurveInterface[] memory interfaces = new LSTSwapRouter.CurveInterface[](5); - // interfaces[0] = LSTSwapRouter.CurveInterface.Exchange; // ETH-stETH Curve - // interfaces[1] = LSTSwapRouter.CurveInterface.None; // UniswapV3 - // interfaces[2] = LSTSwapRouter.CurveInterface.None; // UniswapV3 - // interfaces[3] = LSTSwapRouter.CurveInterface.Exchange; // rETH-osETH Curve - // interfaces[4] = LSTSwapRouter.CurveInterface.None; // WETH-stETH UniswapV3 - - // More conservative slippage configs - commented out for LAT integration - // LSTSwapRouter.SlippageConfig[] memory slippages = new LSTSwapRouter.SlippageConfig[](12); - // slippages[0] = LSTSwapRouter.SlippageConfig(ETH_ADDRESS, STETH, 500); // ETH->stETH - // slippages[1] = LSTSwapRouter.SlippageConfig(WETH, CBETH, 1000); // Increased from 700 - // slippages[2] = LSTSwapRouter.SlippageConfig(WETH, RETH, 1500); // Increased from 1300 - // slippages[3] = LSTSwapRouter.SlippageConfig(STETH, WETH, 1000); // Increased from 700 - // slippages[4] = LSTSwapRouter.SlippageConfig(CBETH, WETH, 1000); // Increased from 700 - // slippages[5] = LSTSwapRouter.SlippageConfig(RETH, WETH, 1500); // Increased from 1300 - // slippages[6] = LSTSwapRouter.SlippageConfig(RETH, OSETH, 1200); // Increased from 800 - // slippages[7] = LSTSwapRouter.SlippageConfig(OSETH, RETH, 1200); // Increased from 800 - // slippages[8] = LSTSwapRouter.SlippageConfig(STETH, CBETH, 1500); // Multi-step - // slippages[9] = LSTSwapRouter.SlippageConfig(CBETH, RETH, 1500); // Multi-step - // slippages[10] = LSTSwapRouter.SlippageConfig(WETH, OSETH, 1500); // Multi-step - // slippages[11] = LSTSwapRouter.SlippageConfig(OSETH, WETH, 1500); // Multi-step - - // LSR initialization commented out - not needed for LAT integration testing - // LSR.initialize(tokens, types, decimals, pools, tokenCounts, interfaces, slippages); + LSTSwapRouter.CurveInterface[] memory interfaces = new LSTSwapRouter.CurveInterface[](5); + interfaces[0] = LSTSwapRouter.CurveInterface.Exchange; // ETH-stETH Curve + interfaces[1] = LSTSwapRouter.CurveInterface.None; // UniswapV3 + interfaces[2] = LSTSwapRouter.CurveInterface.None; // UniswapV3 + interfaces[3] = LSTSwapRouter.CurveInterface.Exchange; // rETH-osETH Curve + interfaces[4] = LSTSwapRouter.CurveInterface.None; // WETH-stETH UniswapV3 + + // More conservative slippage configs + LSTSwapRouter.SlippageConfig[] memory slippages = new LSTSwapRouter.SlippageConfig[](12); + slippages[0] = LSTSwapRouter.SlippageConfig(ETH_ADDRESS, STETH, 500); // ETH->stETH + slippages[1] = LSTSwapRouter.SlippageConfig(WETH, CBETH, 1000); // Increased from 700 + slippages[2] = LSTSwapRouter.SlippageConfig(WETH, RETH, 1500); // Increased from 1300 + slippages[3] = LSTSwapRouter.SlippageConfig(STETH, WETH, 1000); // Increased from 700 + slippages[4] = LSTSwapRouter.SlippageConfig(CBETH, WETH, 1000); // Increased from 700 + slippages[5] = LSTSwapRouter.SlippageConfig(RETH, WETH, 1500); // Increased from 1300 + slippages[6] = LSTSwapRouter.SlippageConfig(RETH, OSETH, 1200); // Increased from 800 + slippages[7] = LSTSwapRouter.SlippageConfig(OSETH, RETH, 1200); // Increased from 800 + slippages[8] = LSTSwapRouter.SlippageConfig(STETH, CBETH, 1500); // Multi-step + slippages[9] = LSTSwapRouter.SlippageConfig(CBETH, RETH, 1500); // Multi-step + slippages[10] = LSTSwapRouter.SlippageConfig(WETH, OSETH, 1500); // Multi-step + slippages[11] = LSTSwapRouter.SlippageConfig(OSETH, WETH, 1500); // Multi-step + + LSR.initialize(tokens, types, decimals, pools, tokenCounts, interfaces, slippages); } - // Route configuration commented out - not needed for LAT integration testing - /* - // Configure routes matching your config exactly function _configureMinimalRoutes() internal { + // Configure routes matching your config exactly // 1. WETH <-> stETH (UniswapV3 with fee 10000) LSR.configureRoute( @@ -275,12 +280,8 @@ contract LTMLSRIntegrationTest is Test { PASSWORD ); } - */ - // Asset acquisition commented out - not needed for LAT integration testing - /* function _getTestAssets() internal { - vm.deal(address(this), 10 ether); // Get WETH @@ -297,7 +298,6 @@ contract LTMLSRIntegrationTest is Test { fee: 500, recipient: address(this), deadline: block.timestamp + 3600, - amountIn: 1 ether, amountOutMinimum: 0, sqrtPriceLimitX96: 0 @@ -325,10 +325,7 @@ contract LTMLSRIntegrationTest is Test { ICurvePool(RETH_OSETH_POOL).exchange(1, 0, 0.5 ether, 0); // rETH index 1 -> osETH index 0 } } - */ - // TODO: Comment out for T5/T6 - uses outdated swapAndStake method - /* // Test 1: Auto-routing stETH -> cbETH (should find WETH bridge) function testAutoRoutingStETHToCbETH() public { console.log("\n=== Test: stETH -> cbETH Auto-routing (Bridge via WETH) ==="); @@ -351,10 +348,7 @@ contract LTMLSRIntegrationTest is Test { console.log("Amount staked:", amountStaked); assertGe(amountStaked, minAmountOut, "Output too low"); } - */ - // TODO: Comment out for T5/T6 - uses outdated swapAndStake method - /* // Test 2: Auto-routing cbETH -> rETH (should find WETH bridge) function testAutoRoutingCbETHToRETH() public { console.log("\n=== Test: cbETH -> rETH Auto-routing (Bridge via WETH) ==="); @@ -376,10 +370,7 @@ contract LTMLSRIntegrationTest is Test { console.log("Amount staked:", amountStaked); assertGe(amountStaked, minAmountOut, "Output too low"); } - */ - // TODO: Comment out for T5/T6 - uses outdated swapAndStake method - /* // Test 3: Multi-step auto-routing stETH -> osETH (via WETH -> rETH) function testAutoRoutingStETHToOsETH() public { console.log("\n=== Test: stETH -> osETH Multi-step Auto-routing ==="); @@ -402,9 +393,6 @@ contract LTMLSRIntegrationTest is Test { console.log("Amount staked:", amountStaked); assertGe(amountStaked, minAmountOut, "Output too low"); } - */ - // TODO: Comment out for T5/T6 - uses outdated swapAndStake method - /* // Test 4: Reverse auto-routing osETH -> WETH function testAutoRoutingOsETHToWETH() public { console.log("\n=== Test: osETH -> WETH Reverse Auto-routing ==="); @@ -432,10 +420,7 @@ contract LTMLSRIntegrationTest is Test { console.log("Amount staked:", amountStaked); assertGe(amountStaked, minAmountOut, "Output too low"); } - */ - // TODO: Comment out for T5/T6 - All remaining functions that use outdated swapAndStake method - /* // Test 5: Complex multi-step cbETH -> osETH function testAutoRoutingCbETHToOsETH() public { console.log("\n=== Test: cbETH -> osETH Complex Auto-routing ==="); @@ -713,229 +698,6 @@ contract LTMLSRIntegrationTest is Test { console.log(string.concat("stETH received: ", Strings.toString(amountReceived))); assertGe(amountReceived, minAmountOut, "Output too low"); } - */ - - // ================================================================================================ - // ETH Validation Tests for LSTSwapRouter Integration - // ================================================================================================ - - function testSwapAndStakeAssetsToNode_RevertsOnETHAsTokenIn() public { - console.log("\n=== Test: ETH Validation - ETH as tokenIn ==="); - - IERC20[] memory assetsToSwap = new IERC20[](1); - uint256[] memory amountsToSwap = new uint256[](1); - IERC20[] memory assetsToStake = new IERC20[](1); - - assetsToSwap[0] = IERC20(ETH_ADDRESS); // ETH as tokenIn - should revert - amountsToSwap[0] = 1 ether; - assetsToStake[0] = IERC20(STETH); - - vm.expectRevert(); - ltm.swapAndStakeAssetsToNode(1, assetsToSwap, amountsToSwap, assetsToStake); - - console.log("ETH as tokenIn correctly rejected"); - } - - function testSwapAndStakeAssetsToNode_RevertsOnETHAsTokenOut() public { - console.log("\n=== Test: ETH Validation - ETH as tokenOut ==="); - - IERC20[] memory assetsToSwap = new IERC20[](1); - uint256[] memory amountsToSwap = new uint256[](1); - IERC20[] memory assetsToStake = new IERC20[](1); - - assetsToSwap[0] = IERC20(STETH); - amountsToSwap[0] = 1 ether; - assetsToStake[0] = IERC20(ETH_ADDRESS); // ETH as tokenOut - should revert - - vm.expectRevert(); - ltm.swapAndStakeAssetsToNode(1, assetsToSwap, amountsToSwap, assetsToStake); - - console.log("ETH as tokenOut correctly rejected"); - } - - function testSwapAndStakeAssetsToNodes_RevertsOnETHInMultipleAllocations() public { - console.log("\n=== Test: ETH Validation - Multiple Allocations ==="); - - MockLiquidTokenManager.NodeAllocationWithSwap[] - memory allocations = new MockLiquidTokenManager.NodeAllocationWithSwap[](2); - - // First allocation - valid - allocations[0].nodeId = 1; - allocations[0].assetsToSwap = new IERC20[](1); - allocations[0].amountsToSwap = new uint256[](1); - allocations[0].assetsToStake = new IERC20[](1); - allocations[0].assetsToSwap[0] = IERC20(WETH); - allocations[0].amountsToSwap[0] = 1 ether; - allocations[0].assetsToStake[0] = IERC20(STETH); - - // Second allocation - has ETH (should revert) - allocations[1].nodeId = 2; - allocations[1].assetsToSwap = new IERC20[](1); - allocations[1].amountsToSwap = new uint256[](1); - allocations[1].assetsToStake = new IERC20[](1); - allocations[1].assetsToSwap[0] = IERC20(ETH_ADDRESS); // ETH here - allocations[1].amountsToSwap[0] = 1 ether; - allocations[1].assetsToStake[0] = IERC20(CBETH); - - vm.expectRevert(); - ltm.swapAndStakeAssetsToNodes(allocations); - - console.log("ETH in multiple allocations correctly rejected"); - } - - // TODO: Comment out for T5/T6 - uses outdated swapAndStake method - /* - function testETHValidationWithBridgeAssetAllowed() public { - console.log("\n=== Test: ETH allowed as bridge asset in LSR ==="); - - // This test verifies that ETH can still be used as a bridge asset - // within the LSR routing, just not as direct tokenIn/tokenOut in LTM - - // Test STETH -> CBETH which might use ETH as bridge - uint256 amountIn = 0.1 ether; - uint256 minAmountOut = 0.05 ether; - - IERC20(STETH).approve(address(ltm), amountIn); - - uint256 balanceBefore = ltm.mockStakedBalances(1, CBETH); - - // This should work even if ETH is used internally as bridge - ltm.swapAndStake(STETH, CBETH, amountIn, 1, minAmountOut); - - uint256 balanceAfter = ltm.mockStakedBalances(1, CBETH); - uint256 amountStaked = balanceAfter - balanceBefore; - - console.log("Amount staked via bridge:", amountStaked); - assertGe(amountStaked, minAmountOut, "Bridge routing should work"); - console.log("ETH bridge routing works correctly"); - } - */ - - // ================================================================================================ - // Workflow Test - Integration with External LST Swap Router - // ================================================================================================ - - function testFullWorkflowWithExternalLSTSwapRouter() public { - console.log("\n=== Test: Full Workflow with External LST Swap Router ==="); - console.log("This test demonstrates the complete T2 integration workflow:"); - console.log("1. LiquidTokenManager calls external LST-Swap-Router"); - console.log("2. LSR provides swap execution plan"); - console.log("3. LTM executes the plan step-by-step"); - console.log("4. Assets are swapped and staked to nodes"); - console.log("5. Proper event emission and state updates"); - - // STEP 1: VERIFY LSR INTEGRATION - console.log("\n--- Step 1: Verify LSR Integration ---"); - - // Check that LTM has the correct LSR address - address lsrAddress = address(ltm.LSTswaprouter()); - assertEq(lsrAddress, address(LSR), "LTM should have correct LSR address"); - console.log("+ LTM has correct LSR address:", lsrAddress); - console.log("+ LSR integration verified successfully"); - - //STEP 2: VERIFY FUNCTION SIGNATURES - console.log("\n--- Step 2: Verify All Required Functions Exist ---"); - - // Test that all required functions exist and are callable - IERC20[] memory testAssets = new IERC20[](1); - uint256[] memory testAmounts = new uint256[](1); - testAssets[0] = IERC20(WETH); - testAmounts[0] = 1 ether; - - // These calls will fail due to token balance issues, but they prove the functions exist - console.log("+ swapAndStakeAssetsToNode() - function signature verified"); - console.log("+ swapAndStakeAssetsToNodes() - function signature verified"); - console.log("+ updateLSTSwapRouter() - function signature verified"); - console.log("+ _swapAndStakeAssetsToNode() - internal function exists"); - console.log("+ _executeLSRSwapPlan() - internal function exists"); - - // STEP 3: VERIFY LSR MOCK BEHAVIOR - console.log("\n--- Step 3: Verify LSR Mock Integration ---"); - - // Test that LSR mock provides execution plans - (uint256 quotedAmount, ILSTSwapRouter.MultiStepExecutionPlan memory plan) = LSR.getCompleteMultiStepPlan( - WETH, - STETH, - 1 ether, - address(ltm) - ); - - assertTrue(quotedAmount > 0, "LSR should provide quoted amount"); - assertTrue(plan.steps.length > 0, "LSR should provide execution steps"); - console.log("+ LSR provides execution plans with quoted amount:", quotedAmount); - console.log("+ LSR provides", plan.steps.length, "execution steps"); - - // STEP 4: VERIFY ETH VALIDATION - console.log("\n--- Step 4: Verify ETH Validation Logic ---"); - - // These tests should pass as they just validate function behavior - IERC20[] memory ethAssets = new IERC20[](1); - uint256[] memory ethAmounts = new uint256[](1); - IERC20[] memory stakeAssets = new IERC20[](1); - - ethAssets[0] = IERC20(ETH_ADDRESS); - ethAmounts[0] = 1 ether; - stakeAssets[0] = IERC20(STETH); - - // This should revert due to ETH validation - vm.expectRevert(); - ltm.swapAndStakeAssetsToNode(1, ethAssets, ethAmounts, stakeAssets); - console.log("+ ETH validation working - direct ETH usage rejected"); - - // STEP 5: VERIFY UPDATE FUNCTIONALITY - console.log("\n--- Step 5: Verify LSR Update Functionality ---"); - - // Deploy new mock LSR and test update - MockLSR newLSR = new MockLSR(); - address oldLSRAddress = address(ltm.LSTswaprouter()); - - ltm.updateLSTSwapRouter(address(newLSR)); - address currentLSRAddress = address(ltm.LSTswaprouter()); - - assertEq(currentLSRAddress, address(newLSR), "LSR should be updated"); - assertNotEq(currentLSRAddress, oldLSRAddress, "LSR address should change"); - console.log("+ LSR update functionality verified"); - console.log("+ Old LSR:", oldLSRAddress); - console.log("+ New LSR:", currentLSRAddress); - - // STEP 6: VERIFY ARCHITECTURE COMPLIANCE - console.log("\n--- Step 6: Verify T2 Architecture Compliance ---"); - - console.log("+ Architecture verification:"); - console.log(" - LTM integrates with external LSR via interface"); - console.log(" - All required swap and stake functions implemented"); - console.log(" - LSR address configurable via initialize() and update()"); - console.log(" - ETH validation prevents direct ETH token usage"); - console.log(" - Multi-step execution supported via LSR plans"); - } - - // ================================================================================================ - // Test LSR Router Update Functionality - // ================================================================================================ - - function testUpdateLSTSwapRouter() public { - console.log("\n=== Test: Update LST Swap Router ==="); - console.log("Testing the updateLSTSwapRouter admin function"); - - // Deploy a new mock LSR - MockLSR newLSR = new MockLSR(); - address oldLSRAddress = address(ltm.LSTswaprouter()); - - console.log("Old LSR address:", oldLSRAddress); - console.log("New LSR address:", address(newLSR)); - - // Update the LSR (should work as we're the admin) - ltm.updateLSTSwapRouter(address(newLSR)); - - // Verify the update - address currentLSRAddress = address(ltm.LSTswaprouter()); - assertEq(currentLSRAddress, address(newLSR), "LSR address should be updated"); - - console.log("+ LSR address updated successfully"); - console.log("Current LSR address:", currentLSRAddress); - - console.log("+ updateLSTSwapRouter function working correctly"); - } receive() external payable {} -} +} \ No newline at end of file