First Flight #18: T-Swap

First Flight #18
Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: high
Valid

Users can potentially receive fewer than expected tokens in `TSwapPool::swapExactOutput`

Summary

The swapExactOutput function does not include any sort of slippage protection. This function is similar to TSwapPool::swapExactInput, where the function has a minOutputAmount. TheswapExactOutput function should have a maxInputAmount.

Vulnerability Details

If market conditions change in the pool before the users transaction goes through, then the user could get a much less favorable swap than they expected.

Impact

Conceptually this is a scenario that could happen

1. The price of 1 WETH is equal to 1,000 USDC
2. User inputs a `swapExactOutput` looking for 1 WETH (Meaning they would pay 1,000 USDC)
1. inputToken = USDC
2. outputToken = WETH
3. outputAmount = 1
4. deadline = whenever
3. The `swapExactOutput` function does not offer a maxInput amount
4. As the transaction is pending in the mempool, the market value changes and there is a price movement, 1 WETH is equal to 5,000 USDC
(Much more than the user expected)
5. The users transaction completes, but now it cost the user 5,000 USDC instead of their expected 1,000 USDC
function testSwapExactOutput() public {
uint256 outputWeth = 1e18;
vm.startPrank(user);
poolToken.approve(address(pool), type(uint256).max);
poolToken.mint(user, 100e18);
vm.stopPrank();
vm.startPrank(liquidityProvider);
weth.approve(address(pool), 500e18);
poolToken.approve(address(pool), 500e18);
pool.deposit(100e18, 100e18, 100e18, uint64(block.timestamp));
vm.stopPrank();
vm.startPrank(user);
pool.swapExactOutput(poolToken, weth, outputWeth, uint64(block.timestamp));
vm.stopPrank();
assert(poolToken.balanceOf(user) < 100e18);
}

Tools Used

--Foundry

Recommendations

It is recommended to include a maxInputAmount so the user only has to spend up to that amount. This helps them predict how much they will spend on the protocol.

function swapExactOutput(
IERC20 inputToken,
+ uint256 maxInputAmount,
.
.
.
inputAmount = getInputAmountBasedOnOutput(outputAmount, inputReserves, outputReserves);
+ if(inputAmount > maxInputAmount){
+ revert();
+ }
_swap(inputToken, inputAmount, outputToken, outputAmount);
Updates

Appeal created

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

Lack of slippage protection in `TSwapPool::swapExactOutput` causes users to potentially receive way fewer tokens

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.