@@ -111,16 +111,32 @@ contract MockAlgebraPool is IAlgebraPool {
111111 address public token0;
112112 address public token1;
113113 address private immutable factory;
114+ bool public shouldApplySlippage;
115+ uint256 public slippageAmount; // How much to reduce the output by
116+ address public targetContract; // The contract we're testing (SwapAlgebra)
114117
115118 constructor (address _token0 , address _token1 , address _factory ) {
116119 token0 = _token0;
117120 token1 = _token1;
118121 factory = _factory;
122+ shouldApplySlippage = false ;
123+ slippageAmount = 0 ;
124+ }
125+
126+ // Set whether this pool should apply slippage to test slippage protection
127+ function setSlippage (bool _shouldApplySlippage , uint256 _slippageAmount ) external {
128+ shouldApplySlippage = _shouldApplySlippage;
129+ slippageAmount = _slippageAmount;
130+ }
131+
132+ // Set the target contract that we're testing
133+ function setTargetContract (address _targetContract ) external {
134+ targetContract = _targetContract;
119135 }
120136
121137 function globalState ()
122138 external
123- view
139+ pure
124140 returns (
125141 uint160 price ,
126142 int24 tick ,
@@ -134,22 +150,28 @@ contract MockAlgebraPool is IAlgebraPool {
134150 return (0 , 0 , 0 , 0 , 0 , 0 , true );
135151 }
136152
137- function swap (address recipient , bool zeroToOne , int256 amountRequired , uint160 limitSqrtPrice , bytes calldata data )
153+ function swap (address recipient , bool zeroToOne , int256 amountRequired , uint160 , bytes calldata data )
138154 external
139155 returns (int256 amount0 , int256 amount1 )
140156 {
141- // Determine which token is being swapped in
157+ // Determine which token is being swapped in/out
142158 address tokenOut = zeroToOne ? token1 : token0;
143159
144160 // Calculate the amount in (positive) and out (negative)
145161 uint256 amountIn = uint256 (amountRequired);
162+ uint256 amountOut = amountIn;
146163
147- // Mock 1:1 swap for testing
164+ // Apply slippage if configured to do so
165+ if (shouldApplySlippage) {
166+ amountOut = amountIn - slippageAmount;
167+ }
168+
169+ // Mock swap with or without slippage
148170 if (zeroToOne) {
149171 amount0 = int256 (amountIn); // Positive (tokens in)
150- amount1 = - int256 (amountIn ); // Negative (tokens out)
172+ amount1 = - int256 (amountOut ); // Negative (tokens out)
151173 } else {
152- amount0 = - int256 (amountIn ); // Negative (tokens out)
174+ amount0 = - int256 (amountOut ); // Negative (tokens out)
153175 amount1 = int256 (amountIn); // Positive (tokens in)
154176 }
155177
@@ -158,10 +180,10 @@ contract MockAlgebraPool is IAlgebraPool {
158180
159181 // Check output token balance
160182 uint256 outTokenBalance = IERC20 (tokenOut).balanceOf (address (this ));
161- require (outTokenBalance >= amountIn , "Insufficient output token balance " );
183+ require (outTokenBalance >= amountOut , "Insufficient output token balance " );
162184
163185 // Transfer output tokens to the recipient
164- IERC20 (tokenOut).transfer (recipient, amountIn );
186+ IERC20 (tokenOut).transfer (recipient, amountOut );
165187 }
166188}
167189
@@ -198,6 +220,20 @@ contract MockAlgebraFactory is IAlgebraFactory {
198220 }
199221}
200222
223+ // Special mock contract to test the slippage protection directly
224+ contract MockSwapAlgebraForSlippage is SwapAlgebra {
225+ constructor (address _algebraFactory , address _uniswapV2Router , address _wzeta )
226+ SwapAlgebra (_algebraFactory, _uniswapV2Router, _wzeta)
227+ {}
228+
229+ // Function that directly tests the slippage protection
230+ function testSlippageProtection (uint256 expectedAmount , uint256 actualAmount ) external pure {
231+ // This mimics the slippage check in the swap function
232+ uint256 minRequiredAmount = calculateMinAmountOutWithSlippage (expectedAmount);
233+ require (actualAmount >= minRequiredAmount, "Slippage tolerance exceeded " );
234+ }
235+ }
236+
201237contract SwapAlgebraTest is Test {
202238 SwapAlgebra public swapAlgebra;
203239 MockUniswapV2Router public mockUniswapV2Router;
@@ -432,4 +468,89 @@ contract SwapAlgebraTest is Test {
432468 vm.expectRevert ("Invalid intermediary token address " );
433469 swapAlgebra.setIntermediaryToken (TOKEN_NAME, address (0 ));
434470 }
471+
472+ function test_CalculateMinAmountOutWithSlippage () public view {
473+ // Test the calculation with different amounts
474+ uint256 amount1 = 1000 ether ;
475+ uint256 amount2 = 1 ether ;
476+ uint256 amount3 = 100 ;
477+
478+ // Using the 1% MAX_SLIPPAGE constant in the contract
479+ uint256 expectedMin1 = 990 ether ; // 1000 - 1%
480+ uint256 expectedMin2 = 0.99 ether ; // 1 - 1%
481+ uint256 expectedMin3 = 99 ; // 100 - 1%
482+
483+ assertEq (
484+ swapAlgebra.calculateMinAmountOutWithSlippage (amount1), expectedMin1, "Incorrect min amount for 1000 ether "
485+ );
486+ assertEq (
487+ swapAlgebra.calculateMinAmountOutWithSlippage (amount2), expectedMin2, "Incorrect min amount for 1 ether "
488+ );
489+ assertEq (swapAlgebra.calculateMinAmountOutWithSlippage (amount3), expectedMin3, "Incorrect min amount for 100 " );
490+
491+ // Test with 0 amount
492+ assertEq (swapAlgebra.calculateMinAmountOutWithSlippage (0 ), 0 , "Incorrect min amount for 0 " );
493+ }
494+
495+ function test_SwapWithSlippageProtection () public {
496+ uint256 initialBalance = inputToken.balanceOf (user);
497+ uint256 swapAmount = AMOUNT;
498+ uint256 expectedOutput = swapAmount - GAS_FEE; // 1:1 swap with gas fee deduction
499+
500+ vm.prank (user);
501+ uint256 amountOut =
502+ swapAlgebra.swap (address (inputToken), address (outputToken), swapAmount, address (gasToken), GAS_FEE);
503+
504+ assertEq (amountOut, expectedOutput, "Incorrect output amount " );
505+ assertEq (inputToken.balanceOf (user), initialBalance - swapAmount, "Input tokens not transferred from user " );
506+ assertEq (outputToken.balanceOf (user), expectedOutput, "Output tokens not received by user " );
507+ assertEq (gasToken.balanceOf (user), GAS_FEE, "Gas tokens not received by user " );
508+ }
509+
510+ function test_RevertWhenSlippageExceeded () public {
511+ // Create a direct mock of SwapAlgebra just for testing slippage
512+ MockSwapAlgebraForSlippage mockSwap =
513+ new MockSwapAlgebraForSlippage (address (mockAlgebraFactory), address (mockUniswapV2Router), address (wzeta));
514+
515+ // Set up test values
516+ uint256 expectedAmount = 1000 ether ;
517+
518+ // Calculate min amount based on 1% slippage
519+ uint256 minRequiredAmount = expectedAmount * 99 / 100 ;
520+
521+ // Test with amount just below the minimum (should fail)
522+ uint256 tooLowAmount = minRequiredAmount - 1 ;
523+
524+ // This should revert with slippage error
525+ vm.expectRevert ("Slippage tolerance exceeded " );
526+ mockSwap.testSlippageProtection (expectedAmount, tooLowAmount);
527+
528+ // This should succeed (amount is exactly at minimum)
529+ mockSwap.testSlippageProtection (expectedAmount, minRequiredAmount);
530+
531+ // This should succeed (amount is above minimum)
532+ mockSwap.testSlippageProtection (expectedAmount, minRequiredAmount + 1 );
533+ }
534+
535+ function test_SwapSucceedsWithSlippageJustUnderLimit () public {
536+ uint256 swapAmount = AMOUNT;
537+
538+ // Configure the mock pool to apply slippage
539+ // Set slippage to be just under 1% of the output amount
540+ uint256 outputAmount = swapAmount - GAS_FEE;
541+ uint256 maxAllowedSlippage = outputAmount / 100 ; // 1%
542+ uint256 acceptableSlippage = maxAllowedSlippage - 1 ; // Just under 1%
543+
544+ MockAlgebraPool pool = MockAlgebraPool (mockAlgebraFactory.poolByPair (address (inputToken), address (outputToken)));
545+ pool.setSlippage (true , acceptableSlippage);
546+
547+ vm.prank (user);
548+ uint256 amountOut =
549+ swapAlgebra.swap (address (inputToken), address (outputToken), swapAmount, address (gasToken), GAS_FEE);
550+
551+ // Expected output is now reduced by the slippage
552+ uint256 expectedOutput = outputAmount - acceptableSlippage;
553+ assertEq (amountOut, expectedOutput, "Incorrect output amount " );
554+ assertEq (outputToken.balanceOf (user), expectedOutput, "Output tokens not received by user " );
555+ }
435556}
0 commit comments