Thankful Ivory Mantaray
Medium
The accrueInterest
function in Mach Finance relies on a constant value borrowRateMaxMantissa
to prevent excessively high borrow rates. This value, however, is not adaptable to different blockchains and can lead to potential protocol instability on faster chains like sonic.
In Mach Finance (and Compound v2), the accrueInterest()
is the common function which calculates interest accrued from the last checkpointed block up to the current block and writes new checkpoint to storage.
There are lines which fetch the interest rate (borrowRateMantissa) as shown below:
/* Calculate the current borrow interest rate */
uint256 borrowRateMantissa = interestRateModel.getBorrowRate(cashPrior, borrowsPrior, reservesPrior);
require(borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high");
This borrowRateMantissa
is fetched from interestRateModel.getBorrowRate
, but the issue here is the check of borrowRateMaxMantissa
:
require(borrowRateMantissa <= borrowRateMaxMantissa, "borrow rate is absurdly high");
This check is to make sure the borrow rate fall under the configured borrowRateMaxMantissa
// Maximum borrow rate that can ever be applied (.0005% / timestamp)
uint256 internal constant borrowRateMaxMantissa = 0.0005e16;
Most of Mach Finance's configuration is mimicking Compound v2; for example, the above borrowRateMaxMantissa
uses the same constant value as in Compound.
The purpose of borrowRateMaxMantissa
is to put the protocol in failure mode when absurd utilization causes the borrow rate to become unreasonably high. It is defined as a constant but should really be changed according to the average block time of the chain the protocol is deployed on.
Assuming block time on L1 where Compound v2 is deployed is 12 seconds, we can safely assume, the current borrowRateMaxMantissa
value should be 12 times lower.
However, on faster chains like Sonic, which have block times of around 0.3-0.5 seconds, the same rate will result in significantly higher annualized rates, potentially leading to an absurdly high borrow rate that could destabilize the protocol.
Another Compound fork on Optimism, Hundred Finance, uses the correct value 0.00004e16.
On faster blockchains like Sonic, the current borrowRateMaxMantissa
can result in significantly higher annualized borrow rates. This can potentially trigger the "absurdly high" borrow rate check more frequently, causing the protocol to enter a failure state and destabilize.
Maximum borrow rate that can ever be applied (.0005% / timestamp)
uint256 internal constant borrowRateMaxMantissa = 0.0005e16;
Example for Ethereum Chain (Block Time = 12 Seconds)
For Ethereum, which has an average block time of 12 seconds, the maximum borrow rate per year can be calculated as follows:
Annualized Borrow Rate for Ethereum = 0.0005 * (365 * 24 * 3600) / 12
= 0.0005% × 31,536,000 seconds per year/12 seconds per block
= 1314% annualized borrow rate
Example for Sonic Chain (Block Time ~0.4 Seconds)
Let’s calculate the annualized borrow rate for Sonic chain with an average block time of 0.4 seconds:
Annualized Borrow Rate for Sonic Chain = 0.0005 * (365 * 24 * 3600) / 0.4
= 0.0005% × 31,536,000 seconds per year/0.4 seconds per block
= 39420% annualized borrow rate
This 39420% is obviously much too high. which potentially trigger the "absurdly high" borrow rate check more frequently, causing the protocol to enter a failure state.
Decide on a maximum borrow rate that the protocol is comfortable with and adjust the borrowRateMaxMantissa
according to the block time of the chain(sonic).