The calculateRcrvUSDAmount
function in StabilityPool contract uses incorrect decimal scaling when converting between DEToken and RToken amounts. This can lead to significant fund losses when users withdraw their deposits, either causing users to receive more RTokens than they originally deposited (protocol loss) or less RTokens than they should (user loss), depending on the decimal configurations of the tokens.
When a user deposits RTokens to the StabilityPool, converting RToken → DEToken is done using the function calculateDeCRVUSDAmount which expressed in math terms as:
Substituting the values of scalingFactor and getExchangeRate():
For withdraw (DEToken → RToken), to maintain accuracy of formular, we need to make RAmt the subject;
Which simplifies to:
However when withdrawing, the rcrvUSDAmount calculated from calculateRcrvUSDAmount the current code uses introduces an incorrect scalingFactor of 10 ** (18 + rTokenDecimals - deTokenDecimals)
;
Looking at eqn and eqn they have different denominators, this shows that the used forumula in calculateRcrvUSDAmount
function is WRONG.
This means when a user deposits RToken they will receive the correct amount of DEToken minted to them, but when they withdraw the value will be WRONGLY highy inflated.
When deTokenDecimals > rTokenDecimals: Users withdraw significantly more RTokens than originally deposited, draining the pool
When deTokenDecimals < rTokenDecimals: Users receive significantly less RTokens than entitled, losing funds
Protocol's accounting system becomes fundamentally broken
Mathematical analysis
Foundry test framework
Update the calculateRcrvUSDAmount
function to use the correct scaling formula:
Both tokens have 18 decimals. Info
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.