RToken is interest baring token and its balance increases overtime. DEToken does not accrue interest and its balance is fixed. However protocol exchanges RToken and DEToken 1:1.
This inconsistency will lead to fund loss of DeToken holders and permanent lock of unclaimed RToken in StabilityPool.
Users receive RToken when they deposit assets into the Reserve Pool. RToken balances increase over time due to interest accrual, represented by the liquidity index.
RToken.balanceOf implementation
DEToken is a Debitum Emptor token of StabilityPool. Users receive DEToken when they deposit RToken into the StabilityPool. Apparently, DEToken is redeemable 1:1 with RToken.
We can notice the inconsistency in the following way:
When RToken is deposited, minted DEToken is RToken.underlyingBalance * liquidityIndexAtDeposit
When DEToken is withdrawed, redeemd RToken is equal to previously minted DEToken.
However StabilityPool's RToken balance has grown into RToken.underlyingBalance * liquidityIndexAtWithdraw
So RToken.underlyingBalance * (liquidityIndexAtWithdraw - liquidityIndexAtDeposit)
amount of RToken will be stuck at StabilityPool
For the depositor, underlyingBalance
shrank to RToken.underlyingBalance * liquidityIndexAtDeposit / liquidityIndexAtWithdraw
Let's do a thought experiment to understand the problem:
Current liquidity index is 1
User deposits 10000 crvUSD into lending pool and mints 10000 RToken
Underlying balance is 10000 = 10000 / liquidityIndex = 10000
RToken balance is 10000
User deposits 10000 RToken into stability pool and mints 10000 DEToken
StabilityPool's RToken balance is 10000
Liquidity index increases to 2
User withdraws 10000 DEToken from stability pool
Now, StabilityPool's RToken balance is 20000
StabilityPool transfers only 10000 RToken to user
User withdraws 10000 RToken from lending pool
Underlyiing balance is now 10000 / liquidityIndex = 5000
User is left with 5000 crvUSD
As we've seen above, there are two issues arised:
Depositor loses fund as liquidity index grows
StabilityPool is left with 10000 RToken, even after user fully burns his DEToken. This RToken is stuck at StabilityPool
Scenario
User deposits 10000 USD to lending pool and mints 10000 RToken
User deposits 10000 RToken into stability pool and mints 10000 DEToken
Some time passes by
User withdraws full DEToken from stabiliy pool
User withdraws full RToken from lending pool
User losts fund and RToken is stuck at stability pool
How to run POC
First, follow steps in hardhat-foundry integration tutorial
Next, create a file test/poc.t.sol
, put the following content and run forge test poc.t.sol -vvv
Addtional Note
This vulnerailbity brings similar issue to this one: https://codehawks.cyfrin.io/c/2025-02-raac/s/cm71l80y80005tgxgs82kzuvi
In order to see this report shows a different root cause, you can optionally apply the patch mentioned in the above report and run the POC.
Console Output
If the patch from the other report is applied:
Depositors lose their asset as time goes by
RToken and its underlying asset is stuck at StabilityPool
Manual Review
When DEToken is withdrawn, RToken balance increment should be handled correctly:
If you apply the above patch and the patch from other report and run the poc again:
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.