First Flight #18: T-Swap

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

Unexpected Transfer in TSwapPool::_swap

Summary

The method TSwapPool::_swap makes an addional transfer if certain condition is met which can be exploited.

Vulnerability Details

On each 10th transfer (defined in TSwapPool::SWAP_COUNT_MAX) it sends 1 ether of the output token to the sender.

Impact

Sending addional weth / pool token by swapping can lead to hackers exploiting this and draining contracts of it's funds.

Tools Used

Manual Review

Proof of concept

  • Add the following test case to TSwapPool.t.sol:

function testSwapingDepositMakesUnexpectedTransfer() public {
vm.startPrank(liquidityProvider);
uint256 initialBalance = 35e18;
weth.approve(address(pool), initialBalance);
poolToken.approve(address(pool), initialBalance);
pool.deposit(initialBalance, initialBalance, initialBalance, uint64(block.timestamp));
vm.stopPrank();
address sampleUser = makeAddr("some_user");
weth.mint(sampleUser, initialBalance);
poolToken.mint(sampleUser, initialBalance);
uint256 amountToSwap = 0.5e18;
// Execute 9 swappings
vm.startPrank(user);
for (uint256 i = 0; i < 9; i++) {
poolToken.approve(address(pool), amountToSwap * 2);
pool.swapExactInput(poolToken, amountToSwap, weth, amountToSwap / 2, uint64(block.timestamp));
console.log(weth.balanceOf(address(pool)));
}
uint256 wethBalanceBeforeUnexpectedTransfer = weth.balanceOf(address(pool));
// Execute one final trasanction to cause the unexpected transfer:
poolToken.approve(address(pool), amountToSwap * 2);
pool.swapExactInput(poolToken, amountToSwap, weth, amountToSwap / 2, uint64(block.timestamp));
uint256 wethBalanceAfterUnexpectedTransfer = weth.balanceOf(address(pool));
console.log("---------------------------");
console.log(wethBalanceAfterUnexpectedTransfer);
assert(wethBalanceAfterUnexpectedTransfer < wethBalanceBeforeUnexpectedTransfer + 1e18);
}
  • Run the following command forge test --mt testSwapingDepositMakesUnexpectedTransfer -vvvvv

  • Analyze the output and notice the unexpected transfer of 1 eth:

34508500359170105780
34030633575025035910
33565839930432792931
33113589941775935295
32673382344512703333
32244742237699550640
31827219373029674516
31420386575423220608
31023838283517237458
---------------------------
29637189199568255800

Recommendations

Remove the logic which makes such transfer:

- uint256 private swap_count = 0;
- uint256 private constant SWAP_COUNT_MAX = 10;
- swap_count++;
- if (swap_count >= SWAP_COUNT_MAX) {
- swap_count = 0;
- outputToken.safeTransfer(msg.sender, 1_000_000_000_000_000_000);
- }
Updates

Appeal created

inallhonesty Lead Judge 11 months ago
Submission Judgement Published
Validated
Assigned finding tags:

In `TSwapPool::_swap` the extra tokens given to users after every swapCount breaks the protocol invariant of x * y = k

Support

FAQs

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