First Flight #18: T-Swap

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

Missing Rounding in getInputAmountBasedOnOutput Calculation

Summary

The getInputAmountBasedOnOutput function does not round up the result by adding 1 to the calculated input amount. This omission can lead to underestimation of the required input amount, which may result in failed transactions due to insufficient input provided.

Vulnerability Details

In automated market makers (AMMs) like Uniswap, the calculation of input amount based on desired output typically involves rounding up the result to ensure that enough input tokens are provided to cover the required output amount and any associated fees. Failing to add 1 to the calculated result can result in scenarios where the provided input amount is just short of what is necessary, causing transactions to revert.

function getInputAmountBasedOnOutput(
uint256 outputAmount,
uint256 inputReserves,
uint256 outputReserves
)
public
pure
revertIfZero(outputAmount)
revertIfZero(outputReserves)
returns (uint256 inputAmount)
{
@> return (inputReserves * outputAmount * 10000) / ((outputReserves - outputAmount) * 997);
}

POC

function testRounding() public {
vm.startPrank(liquidityProvider);
weth.approve(address(pool), 200e18);
poolToken.approve(address(pool), 200e18);
pool.deposit(100e18, 100e18, 100e18, uint64(block.timestamp));
assertEq(pool.balanceOf(liquidityProvider), 100e18);
assertEq(weth.balanceOf(liquidityProvider), 100e18);
assertEq(poolToken.balanceOf(liquidityProvider), 100e18);
assertEq(weth.balanceOf(address(pool)), 100e18);
assertEq(poolToken.balanceOf(address(pool)), 100e18);
pool.deposit(100e18, 100e18, 100e18, uint64(block.timestamp));
assertEq(pool.balanceOf(liquidityProvider), 200e18);
assertEq(weth.balanceOf(liquidityProvider), 0);
// Get input (weth) for an output (pool token) of 10e18
uint256 expected =
pool.getInputAmountBasedOnOutput(10e18, weth.balanceOf(address(pool)), poolToken.balanceOf(address(pool)));
// Can the input gotten above get 10e18 output
uint256 expected2 = pool.getOutputAmountBasedOnInput(
expected, weth.balanceOf(address(pool)), poolToken.balanceOf(address(pool))
);
// this will pass if getInputAmountBasedOnOutput implement rounding with + 1
assert(expected2 >= 10e18);
vm.stopPrank();
}

Impact

  1. Transaction Failures: Users may experience failed transactions if the provided input amount is insufficient to cover the desired output amount plus fees.

  2. User Frustration: Repeated transaction failures due to insufficient input amounts can lead to user frustration and loss of trust in the platform.

  3. Market Inefficiency: Underestimation of input amounts can result in inefficiencies in the liquidity pool, affecting the overall trading experience.

Tools Used

Manual Review

Recommendations

  1. Add Rounding Up: Update the getInputAmountBasedOnOutput function to round up the calculated input amount by adding 1.

  2. Review and Testing: Conduct thorough reviews and tests of all functions that involve input amount calculations to ensure they properly handle rounding.

function getInputAmountBasedOnOutput(
uint256 outputAmount,
uint256 inputReserves,
uint256 outputReserves
)
public
pure
revertIfZero(outputAmount)
revertIfZero(outputReserves)
returns (uint256 inputAmount)
{
- return (inputReserves * outputAmount * 10000) / ((outputReserves - outputAmount) * 997);
+ return (inputReserves * outputAmount * 1000) / ((outputReserves - outputAmount) * 997) + 1;
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
about 1 year ago

Appeal created

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

Rounding is missing

Support

FAQs

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