Closed sherlock-admin closed 1 year ago
2 comment(s) were left on this issue during the judging contest.
Trumpero commented:
invalid, it is expected behavior that rounding down can cause minting 0 of rToken when rTotalSupply is small enough, because the order of calculations minimizes precision loss but ensure never causes an overflow. It will continue minting rTokens if there is enough swap. Additionally, attacker loses his fees because of burning a large amount of rTokens in the scenario, the majority of rTokens will be in protocol and other users.
jkoppel commented:
Very clever. But it has the problem that holding a position in RTokens is equivalent to spreading liquidity across the entire pool. I ran some numbers and found: say the pool is always trading betweens ticks 0 and 1. Someone would need to let the pool claim about 100 million of each token in fees in order to get reinvestLLast to 100 million. But someone else could come in and place only 4999 tokens (less than 1 in 20000 as much) and get the same liquidity between ticks 0 and 1. They would thence take half the rewards from the person who tried to deploy this attack. I'd need to see actual numbers to know that this attack can be pulled off.
n33k
high
Pool: The first liquidity provider can manipulate
calcrMintQty
to steal swap feesSummary
The protocol mints RTokens to liquidity provider to represent his earned fee shares. The formula to calculate the mint amount is manipulatable by liquidity providers. The first liquidity provider can steal almost all the swap fees generated in the protocol.
Vulnerability Detail
The formula to calculate mintQty is
calcrMintQty
.For this formula
rMintQty = rTotalSupply * (reinvestL - reinvestLLast) / reinvestLLast * baseL / (baseL + reinvestL)
, the attacker(i.e., the first liquidity provider) can make it always 0 by decreasingrTotalSupply
and increasingreinvestLLast
.To increase
reinvestLLast
, the attacker can create large swap fees by making a large swap. The large swap will mint rTokens to the attacker and enlargereinvestLLast
andrTotalSupply
. There is almost zero cost of this swap because the attacker is the only LP and most of the fees goes back to him.To decrease
rTotalSupply
, the attacker can callburnRTokens
withisLogicalBurn
set to true. This won't changereinvestLLast
.If
rTotalSupply
is large enough andreinvestLLast
is small enough,rMintQty
will return zero and no new rTokens will be mint for following liquidity providers. The fees still accumulate and will go to exsiting rToken holders, i.e. the attacker and the pool itself.The pool mints 100 rTokens initially to itself, but it doesn't prevent this attack. For example, the attacker can burn his tokens and has 1000 rTokens left. The pool swap fee will goes 10/11 to the attacker.
PoC
Create file
test/PoC.spec.ts
with the following code.Run with
yarn test test/PoC.spec.ts
will print the following logs.userB
is a normal liquidity provider. He gets 0 rToken after userC's swap.To make a comparison with the normal behavior without attack. Comment the following line and run again. This time liquidity provider userB gets his derseved 24998119224 rTokens.
Impact
The attacker can steal all the following swap fees incurred in the pool with very low cost.
Code Snippet
burnRTokens
: https://github.com/sherlock-audit/2023-07-kyber-swap/blob/main/ks-elastic-sc/contracts/Pool.sol#L266-L267calcrMintQty
: https://github.com/sherlock-audit/2023-07-kyber-swap/blob/main/ks-elastic-sc/contracts/libraries/ReinvestmentMath.sol#L12-L13Tool used
Manual Review
Recommendation
No logical burn in
calcrMintQty
.