First Flight #18: T-Swap

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

`TSwapPool::sellPoolTokens` don't sell the pool tokens correctly

Summary

When TSwapPool::sellPoolTokens is called, depending on the balance of the user the swap fails.

Vulnerability Details

Inside the TSwapPool::sellPoolTokens, the function TSwapPool::swapExactOutput is called, as we can see below:

function sellPoolTokens(
uint256 poolTokenAmount
) external returns (uint256 wethAmount) {
return
swapExactOutput( // here
i_poolToken,
i_wethToken,
poolTokenAmount,
uint64(block.timestamp)
);
}

But when the TSwapPool::swapExactOutput is called, is passed the third parameter poolTokenAmount, it means that user want to receive this quantity in weth token, but user may not have this quantity in pool tokens to sell, getting an error of ERC20InsufficientBalance.

We need to call TSwapPool::swapExactInput instead of TSwapPool:swapExactOutput because we only know the quantity that user want to sell in pool token.

Impact

The user may not sell your pool tokens getting and ERC20InsufficientBalance error.

Tools Used

Solidity and Foundry

Proof of Concept

Add the folloing PoC to test/unit/TSwapPool.t.sol:

function testSellPoolTokens() public {
// Add funds to the pool
vm.startPrank(liquidityProvider);
weth.approve(address(pool), 100e18);
poolToken.approve(address(pool), 100e18);
pool.deposit(100e18, 100e18, 100e18, uint64(block.timestamp));
vm.stopPrank();
vm.startPrank(user);
poolToken.approve(address(pool), 100_000e18);
uint256 userPoolTokenInitialBalance = poolToken.balanceOf(user);
uint256 userWethInitialBalance = weth.balanceOf(user);
uint256 expectedUserWethFinalBalance = userWethInitialBalance
+ pool.getOutputAmountBasedOnInput(
userPoolTokenInitialBalance, poolToken.balanceOf(address(pool)), weth.balanceOf(address(pool))
);
pool.sellPoolTokens(userPoolTokenInitialBalance);
assertEq(poolToken.balanceOf(user), 0, "The balance of pool tokens should be 0");
assertEq(
weth.balanceOf(user) == expectedUserWethFinalBalance,
true,
"The balance of WETH should be equal the expected balance"
);
}

Recommendations

You need to call the TSwapPool:swapExactInput to make the swap correctly, for example:

function sellPoolTokens(
uint256 poolTokenAmount
) external returns (uint256 wethAmount) {
- return
- swapExactOutput(
- i_poolToken,
- i_wethToken,
- poolTokenAmount,
- uint64(block.timestamp)
- );
+ uint256 minOutputAmount = getOutputAmountBasedOnInput(
+ poolTokenAmount, i_poolToken.balanceOf(address(this)), i_wethToken.balanceOf(address(this))
+ );
+ return swapExactInput(
+ i_poolToken,
+ poolTokenAmount,
+ i_wethToken,
+ minOutputAmount,
+ uint64(block.timestamp)
+ );
}
Updates

Appeal created

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

`sellPoolTokens` mismatches input and output tokens causing users to receive the incorrect amount of tokens

Support

FAQs

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