-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Intrinsic arbitrage between assets due to price feed deviation threshold #858
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
duplicate-584
satisfactory
satisfies C4 submission criteria; eligible for awards
sufficient quality report
This report is of sufficient quality
Comments
c4-submissions
added
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
labels
Nov 15, 2023
dup of #584 |
raymondfam marked the issue as insufficient quality report |
c4-pre-sort
added
the
insufficient quality report
This report is not of sufficient quality
label
Nov 16, 2023
raymondfam marked the issue as duplicate of #284 |
raymondfam marked the issue as duplicate of #584 |
c4-pre-sort
added
duplicate-584
sufficient quality report
This report is of sufficient quality
and removed
duplicate-284
insufficient quality report
This report is not of sufficient quality
labels
Nov 18, 2023
raymondfam marked the issue as sufficient quality report |
c4-judge
added
the
unsatisfactory
does not satisfy C4 submission criteria; not eligible for awards
label
Dec 1, 2023
fatherGoose1 marked the issue as unsatisfactory: |
fatherGoose1 marked the issue as satisfactory |
c4-judge
added
satisfactory
satisfies C4 submission criteria; eligible for awards
and removed
unsatisfactory
does not satisfy C4 submission criteria; not eligible for awards
labels
Dec 8, 2023
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Labels
3 (High Risk)
Assets can be stolen/lost/compromised directly
bug
Something isn't working
duplicate-584
satisfactory
satisfies C4 submission criteria; eligible for awards
sufficient quality report
This report is of sufficient quality
Lines of code
https://github.com/code-423n4/2023-11-kelp/blob/f751d7594051c0766c7ecd1e68daeb0661e43ee3/src/LRTOracle.sol#L66-L78
Vulnerability details
Impact
Withdrawals have not yet been implemented but I assume it will be implemented in the usual way such that the fraction of total supply of rsETH a user redeems gives him an equal fraction of total assets held, i.e.
received = sharesToRedeem * totalAssets / totalShares
. Thus one should be able to withdraw at most what one deposited.The issue described here is that this invariant does not hold; the minted amount of rsETH may represent a greater value than just deposited. If we imagine that one could immediately withdraw, this means that one can deposit and immediately withdraw for profit.
Proof of Concept
We have something like an ERC4626 vault, where the minted shares are calculated as
depositAmount * totalShares / totalAssets
. The complication here is that we have multiple assets so we cannot use a single balance, but must assign a single value to the held balances of all assets, i.e.depositAmount * totalShares / totalETHValue
.This is indeed how the number of shares to mint is calculated in our case:
where
lrtOracle.getAssetPrice(asset)
is the price given by an oracle (so far only Chainlink is implemented), and wherelrtOracle.getRSETHPrice()
istotalETHInPool / rsEthSupply
wheretotalETHInPool
is the sum of the value of all assets balances. ThusrsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) * rsEthSupply / totalETHInPool
.This is correct in theory, but in practice the price feeds are slightly inaccurate. Chainlink has a deviation threshold of up to 2% or so, which means that it will not update the price unless the true price deviates at least 2%. Thus the price feeds may be off by up to 2%.
Note that for a normal single asset vault the price doesn't matter; it is merely a conversion factor, any discrepancy of which cancels out. It only matters that it be consistent. But when we have multiple assets the price does matter and must be carefully chosen such that one cannot profit by depositing.
Suppose there are two supported assets TIK and TOK.
The pool holds 100 TIK and 0 TOK and has minted 100 rsETH.
The true value of each is currently 1 ETH.
The oracle reports this exactly as 1 for TIK, but as 1.02 for TOK.
A user deposits 100 TOK, which he got for 100 ETH. He is thus minted 100 * 1.02 * 100 / (100 * 1 + 1.02 * 0) = 102 rsETH. However this is of course staked according to its true values.
He now owns 102 out of a total of 202 shares of the assets. If he were to withdraw he would get 102 rsETH * 200 ETH / 202 rsETH = 100.99 ETH, i.e. a profit of 0.99 ETH.
This is not simply because the price is wrong. Note what would have happened if the pool held 0 TIK but 100 TOK instead. Then he would get 100 * 1.02 * 100 / (0 * 1 + 100 * 1.02) = 100 rsETH. And redeem 100 rsETH for 100 * 200 / 200 = 100 ETH. It cancels out.
What happens is that the price discrepancy creates an arbitrage between the assets. It is as if the depositor can deposit TOK, have the protocol trade it for TIK according to its own oracle given price, but redeem 50 TIK and 50 TOK from the real market. He deposits one asset but effectively gets back a distribution of other assets.
Recommended mitigation steps
The contract cannot know the true prices, and the oracle only gives approximate prices. But we do know that the true prices fall within certain ranges. We need to reduce the mint amount, within these ranges, such that no arbitrage is possible.
Assessed type
ERC4626
The text was updated successfully, but these errors were encountered: