First Flight #18: T-Swap

First Flight #18
Beginner FriendlyDeFiFoundry
100 EXP
View results
Submission Details
Severity: medium
Invalid

Invariance break

Summary

Invariance break for the calculation of ∆y.

Vulnerability Details

The documentation specifies that the following invariance must be met: ∆y = (αγ/1+αγ) * y.
However, when calculating values using the function TSwapPool::getOutputAmountBasedOnInput there are cases in which it breaks.

Impact

The swapping does not follow the invariance in the documentation which leads to taking fee that is not as the documentation specifies.
This means that the token pool balance is not as expected and does follow the documentation invariance with fees.

Tools Used

Manual Review

Proof Of Concept

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

function testInvarianceBreak() public {
vm.startPrank(liquidityProvider);
uint256 initialBalance = 100e18;
weth.approve(address(pool), initialBalance);
poolToken.approve(address(pool), initialBalance);
pool.deposit(initialBalance, initialBalance, initialBalance, uint64(block.timestamp));
uint256 amountToSwap = 10e18;
poolToken.approve(address(pool), amountToSwap + 5e18);
pool.swapExactInput(poolToken, amountToSwap, weth, amountToSwap - 1e18, uint64(block.timestamp));
// Values for x and y
uint256 x = initialBalance;
uint256 y = initialBalance;
// Calculate deltaX and deltaY
uint256 deltaX = poolToken.balanceOf(address(pool)) - initialBalance; // Example: 110 - 100 = 10 ETH
uint256 deltaY = initialBalance - weth.balanceOf(address(pool)); // Example: 100 - 90.93 = 9.07 ETH
uint256 rho = 3; // 0.003 represented as 3 in basis points (0.003 * 1000)
// Calculate gamma
uint256 gamma = 1000 - rho; // gamma = 1 - rho
// Calculate alpha
uint256 alpha = (deltaX * 1000) / x; // alpha = (deltaX / x) * 1000 to use integer arithmetic
// Calculate intermediate values for deltaY
uint256 alphaGamma = (alpha * gamma) / 1000; // alpha * gamma in basis points
uint256 onePlusAlphaGamma = 1000 + alphaGamma; // 1 + alpha * gamma in basis points
// Calculate deltaY using the formula: (αγ / (1 + αγ)) * y
uint256 expectedDetalY = (alphaGamma * y) / onePlusAlphaGamma;
assert(expectedDetalY != deltaY);
console.log("Expected delta y: ");
console.log(expectedDetalY);
console.log("Actual delta y: ");
console.log(deltaY);
}
  1. Run the command: forge test --mt testInvarianceBreak -vvvvv

  2. Check that the expected deltaY does not equal to the actual one. For this example the output will be:

Expected delta y:
9008189262966333030
Actual delta y:
9066108938801491315

Recommendations

Rewrite the calculation of the methods TSwapPool::getOutputAmountBasedOnInput and TSwapPool::getInputAmountBasedOnOutput is a way that follows the invariances with fees specified in the documentation:

  • ∆x = (β/(1-β)) * (1/γ) * x

  • ∆y = (αγ/1+αγ) * y

Updates

Lead Judging Commences

inallhonesty Lead Judge
12 months ago

Appeal created

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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