The RToken contract's transfer function incorrectly scales down the transfer amount twice, leading to users transferring significantly less than intended. This double scaling occurs because the user's balance gives underlying amount as transfer amount, and the transfer function scales it down before calling the internal _update function, which also scales it down.
The transfer function in the RToken contract has a critical flaw in its scaling logic:
Incorrect Initial Scaling: The transfer function divides the amount by the normalized income using rayDiv. This is the inverse of what should happen. The amount represents the user's intended transfer amount in underlying asset units. Since the user's amount is in scaled down form, the amount needs to be scaled up using rayMul to get the correct scaled amount to transfer.
Double Scaling in _update: The _update function also scales the amount down by the normalized income. Because the amount has already been incorrectly scaled down in the transfer function, this second scaling results in a double scaling, drastically reducing the actual transfer amount.
Significant Loss of Funds: Users transfer a fraction of the amount they intend to, leading to a substantial loss of funds. The magnitude of the loss is directly related to the normalized income at the time of transfer.
Inconsistent State Changes: The double scaling can lead to inconsistent accounting within the contract, potentially causing issues with calculations with user balances.
Alice has a scaled balance of 110 RTokens (representing 100 underlying units with a normalized income of 1.1).
Alice wants to transfer 100 underlying units to Bob.
The transfer function calculates scaledAmount = 100 / 1.1 = 90.91 (approximately). This is incorrect. It should be 100 * 1.1 = 110.
The _update function then calculates scaledAmount = 90.91 / 1.1 = 82.65 (approximately). This is the double-scaled amount.
Alice only transfers 82.65 RTokens to Bob, even though she intended to transfer 100.
Use this guide to intergrate foundry into your project: foundry
Create a new file FortisAudits.t.sol in the test directory.
Add the following gist code to the file: Gist Code
Run the test using forge test --mt test_FortisAudits_IncorrectTransferScalingInRToken -vvvv.
Logs before the fix:
Logs after the fix:
The transfer function should scale the amount up by the normalized income using rayMul before calling the super.transfer function. This will ensure that the correct scaled amount is transferred.
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.