The getExchangeRate function is hardcoded to return 1e18, ignoring the actual balances of rToken and deTokenwhich is problematic as will be shown below.
Assume:
rTokenDecimals = 18
deTokenDecimals = 18
User deposits 100 rToken (1e20 wei).
deposit(100e18) calls calculateDeCRVUSDAmount(100e18).
calculateDeCRVUSDAmount computes
User receives 100 deToken
If the exchange rate were dynamic (e.g., rToken.balanceOf(pool) / deToken.totalSupply()), the first depositor would receive 100 deToken (since the pool is empty initially). This works correctly here.
Assume:
The pool now holds 100 rToken and 100 deToken (from previous assumption).
A second user deposits 100 rToken.
getExchangeRate() still returns 1e18 (hardcoded).
calculateDeCRVUSDAmount(100e18) again returns 100e18 deToken.
User receives 100 deToken.
second depositor should receive:
The second depositor incorrectly mints 100 deToken instead of 50 deToken, diluting the value of existing deToken holders.
A malicious actor deposits 1 wei of rToken when the pool is empty. getExchangeRate() returns 1e18.
calculateDeCRVUSDAmount(1) returns:
Attacker mints 1 deToken for 1 wei rToken.
The pool now has 1 wei rToken and 1 deToken.
Attacker deposits 1e18 rToken (1 full token)
Attacker now holds 1e18 deToken but only added 1e18 rToken to a pool that already had 1 wei rToken
Attacker exploits the hardcoded rate to mint 1e18 deToken for 1e18 rToken, effectively stealing value from the pool.
The rate is static (1e18), so it doesn’t adjust to reflect the actual rToken/deToken ratio in the pool
Foundry
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.