The malicious first liquidity provider can steal user's fund or prevent others from providing liquidity #123
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
duplicate-442
edited-by-warden
satisfactory
satisfies C4 submission criteria; eligible for awards
Lines of code
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L421
Vulnerability details
Impact
If a malicious user is the first person who is interacting with the pair, he can manipulate the reserve so that stealing fund from users if
minLpTokenAmount == 0
or preventing users from adding liquidity ifminLpTokenAmount != 0
.Proof of Concept
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L217
add
with the following parameters and providing the requiredbaseToken
which is USDC for example.baseTokenAmount
= 1fractionalTokenAmount
= 1minLpTokenAmount
= 1https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L63
addQuote
. So, thetotalSupply = 1
.https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L417
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L90
minLpTokenAmount
parameter equal to zero, Bob front-runs the user and transfers directly to the pair 1000 USDC. By doing so,baseTokenReserves() = 1 + 1000
and total lpToken minted to the user will be equal to zero because of1000 * 1 /(1 + 1000) = 0
:uint256 baseTokenShare = (baseTokenAmount * lpTokenSupply) / baseTokenReserves();
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L421
Although, the user provided 1000 USDC, but zero lpToken is minted for the user. So,
totalSupply = 1
andbaseTokenReserves = 1 + 1000 + 1000
. Now, Bob can remove his liquidity by burning his only lpToken, and receive 2001 USDC (1001 belongs to Bob, and 1000 USDC is user's fund). So, Bob could steal 1000 USDC from the user.minLpTokenAmount
parameter equal to nonzero X, Bob front-runs the user and transfers directly to the pair1000/X
USDC. By doing so, total lpToken minted to the user will be less than X because1000 * 1 /(1 + 1000/X) = 1000 * X / (X + 1000) < X
:uint256 baseTokenShare = (baseTokenAmount * lpTokenSupply) / baseTokenReserves();
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L421
As a result the user's transaction will be reverted because of:
require(lpTokenAmount >= minLpTokenAmount, "Slippage: lp token amount out");
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L80
So, Bob could prevent any user from adding liquidity with nonzero
minLpTokenAmount
. Now, Bob can remove his liquidity by burning his only lpToken, and receive 1 + 1000/X USDC that belongs to him.Tools Used
Recommended Mitigation Steps
totalSupply = 100
andbaseTokenReserves() =100
. By doing so, Bob (as the first person) must add 100 USDC and in return he receives 100 lpToken. To apply the attack when a user is adding 1000 USDC, Bob must transfer directly99.9k + 1
USDC to be able to steal the user's 1000 USDC, because1000 * 100 / (100 + Bob's direct transfer)
. So, Bob's attack requires a large amount of fund which makes it financially unreasonable.pair
. For example, if the protocol mints 1000 lpToken to the pair, Bob must provide almost 1,001,000 USDC to make this1000 * (1000 + 1)/ (1 + Bob's direct transfer)
equal to zero (after rounded down by EVM), which is almost impossible for Bob.The text was updated successfully, but these errors were encountered: