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 {
_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);
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);
i_wethToken.safeTransferFrom(msg.sender, address(this), wethToDeposit);
i_poolToken.safeTransferFrom(
msg.sender,
address(this),
poolTokensToDeposit
);
}