Vulnerability Details and Impact
In RToken.sol#transferFrom
, the _liquidityIndex
is not updated before transfer. The scaledAmount
will be overestimated, leading to the transfer of excess tokens.
function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
uint256 scaledAmount = amount.rayDiv(_liquidityIndex);
return super.transferFrom(sender, recipient, scaledAmount);
}
Due to that _update
function is invoked in default implementation, the amount to transfer will be divided twice.
function _update(address from, address to, uint256 amount) internal override {
uint256 scaledAmount = amount.rayDiv(ILendingPool(_reservePool).getNormalizedIncome());
super._update(from, to, scaledAmount);
}
Tools Used
Manual.
Recommendations
contract RToken is ERC20, ERC20Permit, IRToken, Ownable {
function _accrueIndex() internal {
_liquidityIndex = ILendingPool(_reservePool).getNormalizedIncome();
}
function transfer(address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
_accrueIndex();
uint256 scaledAmount = amount.rayDiv(_liquidityIndex);
return super.transfer(recipient, scaledAmount);
}
function transferFrom(address sender, address recipient, uint256 amount) public override(ERC20, IERC20) returns (bool) {
_accrueIndex();
uint256 scaledAmount = amount.rayDiv(_liquidityIndex);
return super.transferFrom(sender, recipient, scaledAmount);
}
function _update(address from, address to, uint256 amount) internal override {
super._update(from, to, scaledAmount);
}
}