Kinetic Disclosed Report

Audit report Kinetic Audit Contest

Inappropriate Maximum Borrow Rate for Fast Block Times on the Flare Network

Company
Created date
Feb 14 2025

Target

https://github.com/kinetic-market/public-money-market-contracts

Vulnerability Details

The accrueInterest function in the Public Money Market 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 Flare Network.

uint internal constant borrowRateMaxMantissa = 0.0005e16;

Validation steps

In the Public Money Market (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 */
        uint 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

uint internal constant borrowRateMaxMantissa = 0.0005e16;

Most of Public Money Market'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 Flare Network, which have block times of around 3 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(https://optimistic.etherscan.io/address/0x0145BE461a112c60c12c34d5Bc538d10670E99Ab#code#F2#L32).

Example for Ethereum Chain (Block Time = 12 Seconds)

uint256 internal constant borrowRateMaxMantissa = 0.0005e16;

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 the Flare Network (Block Time ~3 Seconds)

Let’s calculate the annualized borrow rate for the Flare Network with an average block time of 3 seconds:

Annualized Borrow Rate for the Flare Network = 0.0005 * (365 * 24 * 3600) / 3

= 0.0005% × 31,536,000 seconds per year/3 seconds per block

= 5256% annualized borrow rate

This 5256% is obviously much too high. which potentially trigger the "absurdly high" borrow rate check more frequently, causing the protocol to enter a failure state.

Mitigation Decide on a maximum borrow rate that the protocol is comfortable with and adjust the borrowRateMaxMantissa according to the block time of the chain( Flare Network).

CommentsReport History
Comments on this report are hidden
Details
Statedisclosed
Severity
None
Bounty$36
Visibilitypartially
VulnerabilityOther
Participants (3)
company admin
author