make token per liquidity very high by direct early token transfer to Pair contract which would cause users to lose funds when they provide liquidity #338
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#L411-L428
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L63-L99
Vulnerability details
Impact
Function
addQuote()
calculates the amount of LP tokens received for adding a given amount of base tokens and fractional tokens. attacker can manipulate token per liquidity value and make it so high that whenever users wants to provide liquidity they lose a lot of funds because of the rounding. by doing this attacker can steal other users funds and make Pair contract to be useless.Proof of Concept
This is
addQuote()
code:As you can see the lp token amount is calculated as a share of existing deposits. If there are no existing deposits, then initializes to
sqrt(baseTokenAmount * fractionalTokenAmount)
. and in the functionadd()
this amount is used to mint lp token for user.So to exploit this attacker can perform this steps:
10 * 1e18
fractional token.add()
and contract would mint 1 LP token for attacker.10 * 1e18
fractional token to contract address and1000 * 1e18 - 1
amount of baseToken to contract address.lpToken.totalSupply()
is 1,baseTokenReserves()
is1000 * 1e18
,fractionalTokenReserves()
is10 * 10e18
.1600 * 1e18
baseToken and16 * 10e18
fractional token as liquidity and he would calladd()
for this.addQuote()
would calculate lp token amount as:baseTokenShare = (baseTokenAmount * lpTokenSupply) / baseTokenReserves() = 1500 * 10e18 * 1 / 1000 * 1e18 = 1
,fractionalTokenShare = (fractionalTokenAmount * lpTokenSupply) / fractionalTokenReserves() = 16 * 1e18 * 1 / 10 * 10e18 = 1
andlpTokenAmount = Math.min(baseTokenShare, fractionalTokenShare) = min(1,1) =1
and contract would mint 1 lp token for user and transfer1600 * 1e18
baseToken and16 * 10e18
fractional token from user.lpToken.totalSupply()
is 2,baseTokenReserves()
is2600 * 1e18
,fractionalTokenReserves()
is26 * 10e18
.remove(1)
and contract would transfer 50% of the liquidity to user (because user1 has 1 LP token of the total 2 LP tokens) (calculations are done in theremoveQuote()
) and user1 would receive1300 * 1e18
baseToken and13 * 10e18
fractional token.1300 * 1e18
baseToken and13 * 10e18
fractional token. and as you can see user1 add token and removed them and lost300 * 1e18
baseToken and3 * 10e18
fractional token immediately and attacker took them.even if user1 wants to specify
minLpTokenAmount
when callingadd()
function it would cause whole transaction to fail. the problem is that attacker manipulated token per share value and make it so high that users would lose their liquidity deposits through rounding error in calculations. the numbers in the POC was just an example and scenario can be different and the attack would still be effective.the early direct transfer of funds can be done by attacker with smart contract (which create Pair and add liquidity and transfer funds in one transaction) for popular NFT collection and merkle root 0x0 and popular baseTokens (like ETH) so attacker can perform the attack for common Pairs contract. also attacker doesn't need to be the first liquidity provider and if the first liquidity provider provide small amount of tokens attacker can directly transfer the tokens and perform the attack.
Tools Used
VIM
Recommended Mitigation Steps
one simple and fast solution would be add some precision for LP token amount so that token per liquidity can't be manipulate so easily.
The text was updated successfully, but these errors were encountered: