diff --git a/src/MevEthRouter.sol b/src/MevEthRouter.sol index 766936c..be5534c 100644 --- a/src/MevEthRouter.sol +++ b/src/MevEthRouter.sol @@ -302,7 +302,7 @@ contract MevEthRouter is IUniswapV3SwapCallback, IMevEthRouter { /// @notice Fetches swap data for each pair and amounts given an input amount /// @param amountIn Amount in for first token in path /// @param amountOutMin Min amount out - /// @return swaps Array Swap data for each user swap in path + /// @return swaps struct for split order details function getStakeRoute(uint256 amountIn, uint256 amountOutMin) public view returns (Swap memory swaps) { swaps.pools = _getPools(); swaps.tokenIn = address(WETH09); @@ -324,7 +324,7 @@ contract MevEthRouter is IUniswapV3SwapCallback, IMevEthRouter { /// @param useQueue Use redeem queue /// @param amountIn Amount in for first token in path /// @param amountOutMin Min amount out - /// @return swaps Array Swap data for each user swap in path + /// @return swaps struct for split order details function getRedeemRoute(bool useQueue, uint256 amountIn, uint256 amountOutMin) public view returns (Swap memory swaps) { swaps.pools = _getPools(); swaps.tokenIn = address(MEVETH); @@ -343,6 +343,29 @@ contract MevEthRouter is IUniswapV3SwapCallback, IMevEthRouter { } } + /// @notice Amount out expected from stake + /// @param amountIn Amount in for first token in path + /// @return amountOut Expected amountOut + /// @return swaps struct for split order details + function amountOutStake(uint256 amountIn) external view returns (uint256 amountOut, Swap memory swaps) { + swaps = getStakeRoute(amountIn, 1); + for (uint256 j; j < 8; j = _inc(j)) { + amountOut += swaps.pools[j].amountOut; + } + } + + /// @notice Amount out expected from redeem + /// @param useQueue Use redeem queue + /// @param amountIn Amount in for first token in path + /// @return amountOut Expected amountOut + /// @return swaps struct for split order details + function amountOutRedeem(bool useQueue, uint256 amountIn) external view returns (uint256 amountOut, Swap memory swaps) { + swaps = getRedeemRoute(useQueue, amountIn, 1); + for (uint256 j; j < 8; j = _inc(j)) { + amountOut += swaps.pools[j].amountOut; + } + } + /// @dev populates and returns Reserve struct array for each pool address /// @param isDeposit true if deposit eth, false if redeem /// @param pools 5 element array of Pool structs populated with pool addresses diff --git a/src/interfaces/IMevEthRouter.sol b/src/interfaces/IMevEthRouter.sol index 67c666d..4c64423 100644 --- a/src/interfaces/IMevEthRouter.sol +++ b/src/interfaces/IMevEthRouter.sol @@ -24,6 +24,8 @@ interface IMevEthRouter { Pool[8] pools; // 8 pools (sushi, univ2, univ3 (3 pools), mevEth, Balancer Gyro ECLP, Curve V2) } + function amountOutStake(uint256 amountIn) external view returns (uint256 amountOut, Swap memory swaps); + function amountOutRedeem(bool useQueue, uint256 amountIn) external view returns (uint256 amountOut, Swap memory swaps); function stakeEthForMevEth(address receiver, uint256 amountIn, uint256 amountOutMin, uint256 deadline) external payable returns (uint256 shares); function stakeEthForMevEthRaw( address receiver, diff --git a/test/MevEthRouter.t.sol b/test/MevEthRouter.t.sol index 108f2df..90277e1 100644 --- a/test/MevEthRouter.t.sol +++ b/test/MevEthRouter.t.sol @@ -40,6 +40,32 @@ contract MevEthRouterTest is DSTest { receive() external payable { } + /// @dev Fuzz test amountOut Stake call + function testamountOutStake(uint80 amountIn) external { + vm.assume(amountIn > 0.1 ether); + vm.assume(amountIn < 100_000 ether); + // vm.deal(address(this), amountIn); + bytes memory input = abi.encodeWithSelector(router.amountOutStake.selector, amountIn); + (, bytes memory data) = address(router).staticcall(input); + (uint256 amountOut, ) = abi.decode(data, (uint256, IMevEthRouter.Swap)); + assertGt(amountOut, 0); + } + + /// @dev Fuzz test amountOut Redeem call + function testamountOutRedeem(uint80 amountIn) external { + vm.assume(amountIn > 0.1 ether); + vm.assume(amountIn < 10_000 ether); + // vm.deal(address(this), amountIn); + bool useQueue; + if (amountIn > 15 ether){ + useQueue = true; + } + bytes memory input = abi.encodeWithSelector(router.amountOutRedeem.selector, useQueue, amountIn); + (, bytes memory data) = address(router).staticcall(input); + (uint256 amountOut, ) = abi.decode(data, (uint256, IMevEthRouter.Swap)); + assertGt(amountOut, 0); + } + /// @notice Fuzz test staking Eth with static call for route /// @dev default client side staking eth process, using static call on route finder to save gas function testStakeEthRaw(uint80 amountIn) external {