loss of precision is too high when accuring interest
When intereste accures, we are calling
uint256 interestAmount;
{
uint256 interestRate = IIRM(irm).getInterestRate(address(this), trancheIndex, totalDeposit, totalBorrow);
interestAmount = (trancheBorrowAmount_ * interestRate * timePassed) / 365 days / IRM_SCALE;
}
note that the loss of precision is too high:
interestAmount = (trancheBorrowAmount_ * interestRate * timePassed) / 365 days / IRM_SCALE;
we are dividing 365 days and then divde by IRM_SCALE (which is 1e9)
combing the fact taht the IRM_SCALE is hardcoded to 1e9
and if the time passed between two accuring is small,
and the underlying token have low decimals (6 decimals, even two decimals)
the interest accured will be always rounded to 0
In tests/MockERC20.sol,
the decimal is hardcoded to 18
we change the hardcode decimal to 6
and we add the POC below in TestOmniToken.t.sol
function test_Accrue_POC_Low_decimal() public {
setUpBorrow();
(uint256 tda0, uint256 tba0,,) = oToken.tranches(0);
(uint256 tda1, uint256 tba1,,) = oToken.tranches(1);
(uint256 tda2, uint256 tba2,,) = oToken.tranches(2);
uint256 td = tda0 + tda1 + tda2;
uint256 borrowAmount = 10 * (10 ** uToken.decimals());
IOmniPool(pool).borrow(0, address(oToken), borrowAmount);
uint256 time_elapse = 120 seconds;
vm.warp(time_elapse);
uint256 interestAmount;
{
uint256 interestRate = irm.getInterestRate(address(oToken), 0, td, borrowAmount);
interestAmount = borrowAmount * interestRate * time_elapse / 365 days / oToken.IRM_SCALE();
}
uint256 feeInterestAmount = interestAmount * oToken.RESERVE_FEE() / oToken.FEE_SCALE();
interestAmount -= feeInterestAmount;
oToken.accrue();
vm.warp(time_elapse * 2);
oToken.accrue();
vm.warp(time_elapse * 4);
oToken.accrue();
}
we are accuring the interest every two minutes
before running the POC
we import the
import "forge-std/console.sol";
In OmniToken.sol
and add the console.log to log the interest
{
uint256 interestRate = IIRM(irm).getInterestRate(address(this), trancheIndex, totalDeposit, totalBorrow);
// @audit
// this can be trancated to 0
interestAmount = (trancheBorrowAmount_ * interestRate * timePassed) / 365 days / IRM_SCALE;
console.log("interestAmount", interestAmount);
}
then we run the POC
forge test -vv --match-test "test_Accrue_POC_Low_decimal"
the output is
Running 1 test for src/tests/TestOmniToken.t.sol:TestOmniToken
[PASS] test_Accrue_POC_Low_decimal() (gas: 737833)
Logs:
interestAmount 0
interestAmount 0
interestAmount 0
this mean within every two minutes time elapse, the interest is round down to 0
and the accure function is called in every borrow / withdraw / transfer, so the interest will be rounded down heaviliy
or user can keep calling accure for every two minutes (or x minutes) to avoid paying interest
Manual Review
modify the interest, do not do muliplication before division to avoid precision loss
do not hardcode IRM_SCALE and consider token decimals when accuring interess
Decimal
The text was updated successfully, but these errors were encountered:
All reactions