user funds loos because function add() doesn't return the extra amount of baseToken or fractionalToken to the user #340
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
duplicate-376
edited-by-warden
satisfactory
satisfies C4 submission criteria; eligible for awards
upgraded by judge
Original issue severity upgraded from QA/Gas by judge
Lines of code
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L63-L99
https://github.com/code-423n4/2022-12-caviar/blob/0212f9dc3b6a418803dbfacda0e340e059b8aae2/src/Pair.sol#L417-L428
Vulnerability details
Impact
Function
add()
adds liquidity to the pair, it transfers base token and fractional token from user and mint lp token for user, but during the calculation of the lp token amount contract take minimum amount of lp token based on percentage of user supplied base and fractional token to contract balance, but contract won't return the extra amount of base token or fractional token to the user. users don't know exactly how much of each token is needed they may send extra tokens to make sure transaction won't get reverted because of low amount of tokens but this would cause to lose those extra tokens. and when a user makes mistake send very large amount of base or fractional tokens those all would be lost.Proof of Concept
This is
add()
code:As you can see code calls
addQuote()
and mint amount of lp tokens returned by that function for user and there is no logic to return extra base token or fractional token to the user.This is
addQuote()
code:As you can see to calculate the amount of lp token contract calculates amount of lp tokens as a fraction of existing reserves and then took the minimum values. so when this scenario happens:
100 * 1e18
base token balance and50 * 1e18
fractional token balance andlpTokenSupply
is10 * 1e18
.add(11 * 1e18 base token, 5 * 1e18 fractional token, 1 * 1e18 minimum lp token)
.baseTokenShare = (baseTokenAmount * lpTokenSupply) / baseTokenReserves() = (11 * 1e18 * 10 *1e18) / (100 * 1e18) = 11 * 1e17
andfractionalTokenShare = (fractionalTokenAmount * lpTokenSupply) / fractionalTokenReserves() = (5 * 1e18 * 10 * 1e18) / (50 * 1e18) = 1e18
andlpTokenAmount = min(11 * 1e17 , 1e18) = 1e18
. so contract would mint1e18
LP token for user1 and transfer11 * 1e18 base token
and5 * 1e18 fractional token
from user to contract address.111 * 1e18
base token balance and55 * 1e18
fractional token balance andlpTokenSupply
is11 * 1e18
.1e18
lp token which if user wants to remove the liquidity user would receivebaseTokenOutputAmount = (baseTokenReserves() * lpTokenAmount) / lpTokenSupply = (111 * 1e18 * 1e18) / (11 * 118) = 10*1e18
base token andfractionalTokenOutputAmount = (fractionalTokenReserves() * lpTokenAmount) / lpTokenSupply = (55 * 1e18 * 1e18) / (11 * 118) = 5 * 1e18
fractional token amount.1e18
amount of base token in doing so.the problem is that in the step #3 contract calculates lp token amount based on user supplied base token and fractional token and take the minimum between them but in the token that is not generating minimum lp tokens, user supplied more tokens (in the above example base token) so contract should return those extra tokens. in the above example the
1e18
lp token worth10 * 1e18
base token and user supplied11 * 1e18
amount. so contract should transfer that extra amount after calculating the lp amount.This issue would happen in each call to
add()
function as users don't know exactly how much of each token they need to supply and to make sure transaction won't fail they would supply more tokens and it would make them to lose funds. in each call one of the base token amount or fractional token amount would generate lower lp token and user other tokens would have some extra amount.And in cases where user makes a mistake and transfer a lot of tokens from one of the base token or fractional token those tokens would be lost.
Tools Used
VIM
Recommended Mitigation Steps
after calculating the amount of minting lp tokens, calculate the amount of base token and fractional token required based on lp token amount and transfer those exact required amount of tokens to contract address and return the extra amount if necessary. something like this:
The text was updated successfully, but these errors were encountered: