First Flight #18: T-Swap

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

The first depositor can set the amount of pool tokens to 0, which will eventually stop the pool function.

Summary

_addLiquidityMintAndTransfer function does not check if poolTokensToDeposit is zero.

Vulnerability Details

Initial swap ratio is determined by deposit amounts of first depositor.

function deposit(
uint256 wethToDeposit,
uint256 minimumLiquidityTokensToMint,
uint256 maximumPoolTokensToDeposit,
uint64 deadline
)
external
revertIfZero(wethToDeposit)
returns (uint256 liquidityTokensToMint)
{
if (wethToDeposit < MINIMUM_WETH_LIQUIDITY) {
revert TSwapPool__WethDepositAmountTooLow(
MINIMUM_WETH_LIQUIDITY,
wethToDeposit
);
}
if (totalLiquidityTokenSupply() > 0) {
__SNIP__
} else {
// This will be the "initial" funding of the protocol. We are starting from blank here!
// We just have them send the tokens in, and we mint liquidity tokens based on the weth
_addLiquidityMintAndTransfer(
wethToDeposit,
maximumPoolTokensToDeposit,
wethToDeposit
);
liquidityTokensToMint = wethToDeposit;
}
}

As you can see in above code, there is not any validation for maximumPoolTokensToDeposit if totalLiquidityTokenSupply is 0.

function _addLiquidityMintAndTransfer(
uint256 wethToDeposit,
uint256 poolTokensToDeposit,
uint256 liquidityTokensToMint
) private {
_mint(msg.sender, liquidityTokensToMint);
emit LiquidityAdded(msg.sender, poolTokensToDeposit, wethToDeposit);
// Interactions
i_wethToken.safeTransferFrom(msg.sender, address(this), wethToDeposit);
i_poolToken.safeTransferFrom(
msg.sender,
address(this),
poolTokensToDeposit
);
}

The _addLiquidityMintAndTransfer function doesn't check for this either.
So the first depositor (malicious user) can send MINIMUM_WETH_LIQUIDITY of weth and 0 of pool tokens to stop the pool function.
All deposits do not require users to send any amount of pool tokens. Since reserve of pool token are 0 after first deposit, it will always be 0.
If outputReserves is 0, the getOutputAmountBasedOnInput transaction is reverted.
The getInputAmountBasedOnOutput transaction is also reverted.

Impact

The main functionality of the pool contract is disrupted by a first depositor attack.

Tools Used

Manual review

Recommendations

If the deposit amount of pool token is 0 when making the first deposit, please revert it.

function _addLiquidityMintAndTransfer(
uint256 wethToDeposit,
uint256 poolTokensToDeposit,
uint256 liquidityTokensToMint
-- ) private {
++ ) private revertIfZero(poolTokensToDeposit) {
_mint(msg.sender, liquidityTokensToMint);
emit LiquidityAdded(msg.sender, poolTokensToDeposit, wethToDeposit);
// Interactions
i_wethToken.safeTransferFrom(msg.sender, address(this), wethToDeposit);
i_poolToken.safeTransferFrom(
msg.sender,
address(this),
poolTokensToDeposit
);
}
Updates

Appeal created

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

_addLiquidityMintAndTransfer function does not check if poolTokensToDeposit is zero.

Support

FAQs

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

Give us feedback!