The RToken contract has a rescueToken function to recover non-main assets sent to it accidentally, but this function can only be called by the Reserve Pool (LendingPool). However, the LendingPool lacks any mechanism to trigger this rescue functionality, effectively leaving any mistakenly sent tokens permanently locked in the RToken contract.
The issue stems from a misalignment in the permission model between the RToken and LendingPool contracts. Let's analyze this in detail:
RToken's rescue mechanism:
This function is designed to rescue non-main assets, but it's restricted to be called only by the Reserve Pool (LendingPool) through the onlyReservePool modifier:
LendingPool's rescue mechanism:
The LendingPool's rescueToken function can only rescue tokens directly held by the LendingPool contract. It has no mechanism to trigger RToken's rescue function.
The core issue arises because:
RToken expects LendingPool to coordinate token rescues
LendingPool has no functionality to coordinate with RToken's rescue mechanism
The ownership and permission model doesn't align between the contracts
There's no administrative bypass or alternative rescue path
This creates a situation where tokens accidentally sent to the RToken contract become permanently locked unless they are the main asset (crvUSD in this case).
Alice accidentally sends 50 USDC tokens to the RToken contract address
The RToken contract has a rescueToken function, but it requires LendingPool to call it.
LendingPool has no mechanism to call RToken's rescueToken function
The USDC tokens are now permanently locked in the RToken contract
Even the protocol owner cannot rescue these tokens as both contracts' rescue mechanisms are misaligned
Any non-main asset tokens accidentally sent to the RToken contract will be permanently locked with no recovery mechanism available. This could lead to permanent loss of user funds if they accidentally send tokens to the RToken contract address.
Manual review
Two possible solutions:
Modify RToken's rescueToken to be callable by owner instead of ReservePool:
Add a function in LendingPool to trigger RToken's rescue mechanism:
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.