A malicious early user/attacker can manipulate the lpToken's pricePerShare to take an unfair share of future users' deposits #470
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
duplicate-442
satisfactory
satisfies C4 submission criteria; eligible for awards
Lines of code
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L275-L286
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L63-L100
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L417-L428
Vulnerability details
Impact
A well known attack vector for almost all shares based liquidity pool contracts, where an early user can manipulate the price per share and profit from late users' deposits because of the precision loss caused by the rather large value of price per share..
Proof of Concept
Attacker add 1 nft and can receive 1e18 value of
fractionalTokenAmount
at line 282uint256 fractionalTokenAmount = wrap(tokenIds, proofs);
Now, at line 285, add function is called with baseTokenAmount = 1e18, fractionalTokenAmount = 1e18, and minLpTokenAmount is some x amount.
In add function, at line 77,
addQuote
is called.lpTokenAmount = addQuote(baseTokenAmount, fractionalTokenAmount);
since it is first deosit, the lpTokenSupply will be zero, so else part is executed and the
return Math.sqrt(baseTokenAmount * fractionalTokenAmount);
The total amount of lptoken is 1e18.
Then the attacker can send 10000e18 - 1 of baseToken tokens and inflate the price per share from 1.0000 to an extreme value of 1.0000e22 ( from (1 + 10000e18 - 1) / 1) .
As a result, the future user who deposits 19999e18 will only receive 1 wei (from 19999e18 * 1 / 10000e18) of shares token.
They will immediately lose 9999e18 or half of their deposits if they sell and liquidate right after the deposit().
Tools Used
Manual review
Recommended Mitigation Steps
Consider requiring a minimal amount of share tokens to be minted for the first minter, and send a port of the initial mints as a reserve to the DAO so that the pricePerShare can be more resistant to manipulation.
The text was updated successfully, but these errors were encountered: