First Flight #18: T-Swap

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

In `_swap` function users are rewarded with extra tokens potentially draining the entire protocol

Summary

  • In the _swap function, for each 10 swaps executed, the user is rewarded with 1_000_000_000_000_000_000 extra tokens. This extra incentive breaks the protocol invariant of x * y = k meaning that over time the protocol funds will be drained.

Vulnerability Details

  • Block where for each 10 swaps executed, user is rewarded with extra tokens.

swap_count++;
if (swap_count >= SWAP_COUNT_MAX) {
swap_count = 0;
outputToken.safeTransfer(msg.sender, 1_000_000_000_000_000_000);
}
  • PoC - Copy this test into TSwapPool.t.sol

function testSwapExactOutputBreaksInvariant() public {
vm.startPrank(liquidityProvider);
weth.approve(address(pool), 100e18);
poolToken.approve(address(pool), 100e18);
pool.deposit(100e18, 100e18, 100e18, uint64(block.timestamp));
vm.stopPrank();
uint256 outputAmount = 1e17;
vm.startPrank(user);
poolToken.approve(address(pool), type(uint256).max);
poolToken.mint(user, 100e18);
for (uint256 i = 0; i < 9; i++) {
pool.swapExactOutput({
inputToken: poolToken,
outputToken: weth,
outputAmount: outputAmount,
deadline: uint64(block.timestamp)
});
}
uint256 startingY = weth.balanceOf(address(pool));
int256 expectedDeltaY = int256(-1) * int256(outputAmount);
//This is the 10th swap where user receives extra tokens (breaking the invariant)
pool.swapExactOutput({
inputToken: poolToken,
outputToken: weth,
outputAmount: outputAmount,
deadline: uint64(block.timestamp)
});
vm.stopPrank();
uint256 endingY = weth.balanceOf(address(pool));
int256 actualDeltaY = int256(endingY) - int256(startingY);
//The change of token balance of weth (∆y) is not the expected!
assertEq(expectedDeltaY, actualDeltaY); // expectedDeltaY -1e17 != actualDeltaY -1.1e18
}

Impact

  • A user could maliciously drain the protocol's funds by repeatedly executing swaps and collecting the extra incentives provided by the protocol.

Tools Used

  • Manual review

Recommendations

  • Remove the extra rewards implementation (as this mechanism is not described in the documentation)

- swap_count++;
- if (swap_count >= SWAP_COUNT_MAX) {
- swap_count = 0;
- outputToken.safeTransfer(msg.sender, 1_000_000_000_000_000_000);
- }
  • Implement a system similar to fee collection.

  • Change the protocol invariant to incorporate this extra reward.

Updates

Appeal created

inallhonesty Lead Judge 12 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.