TRUST Summit | Nov 3, 2025 | NYCWhere decision-makers define the next chapter of secure blockchain adoption.
Learn more

Aave Borrow Rate Tuning: A Practical Guide

12 min read

Aave’s borrow rate model is one of the most mathematically elegant mechanisms in decentralized lending. It dynamically adjusts interest based on utilization, discouraging over-borrowing while promoting capital efficiency. Yet elegance can be unforgiving: the model is highly sensitive to parameter choices — especially in forks — where a “small” tweak can reshape the entire curve.

If you’re shipping or forking an Aave-style market, here’s what you’ll learn in the next 30 minutes:

  • Understand how Aave’s variable borrow-rate model works — both mathematically and in code.
  • See simulations that reveal misconfigurations capable of freezing markets.
  • Identify systemic risks when forking Aave or changing parameters without full context.
  • Apply practical, holistic checklists and recommendations to evaluate borrow-rate configurations.

TL;DR

Our analysis highlights a critical insight: parameter tuning in interest-rate models is not a trivial task. Even a mathematically sound model like Aave’s can behave harmfully if its configuration is misunderstood, copy-pasted, or tweaked without grasping the implications.

Recommendations for Auditors

  • Check for parameter sanity: Validate that and that all slopes are within reasonable economic bounds. Be cautious of extreme values like > 1000% or  > 100%.
  • Simulate before signing off: Edge cases are not always visible through code alone. Simple simulations can reveal cliffs, inversions, or plateaus in the rate curve.
  • Look for economic consistency: Ensure that the model aligns with supply-demand logic. If higher utilization results in lower rates, that’s a red flag.

Recommendations for Developers (Especially on Forks)

  • Don’t blindly copy parameters: A change from to may seem minor, but can multiply the post-optimal slope effect by 20×.
  • Test unusual utilization regimes: Validate behavior at very low and very high utilization, not just around the target range.
  • Document the intention: If you choose non-standard parameters, explicitly state the rationale. This aids future audits and protects against misconfiguration.

In many Aave forks, teams tweak a single parameter to “optimize” behavior without seeing the second-order effects. That’s deceptively dangerous.

A small change in one parameter, like optimalUtilization, impacts the entire shape of the interest rate curve. Changing from 80% to 99% means that the denominator in the term shrinks from 20% to 1%, multiplying the slope effect by 20×. What was once a gradual increase becomes a vertical wall.

Seemingly safe settings — like flat pre-optimal regions or low — can hide risk until the protocol hits a hard cliff.

Borrow Rate Model: Stable vs Variable Rates

Aave offers borrowers two interest rate options: Variable and Stable. When borrowing, users actively choose between these two models. Both rate types operate simultaneously within the same pools, with users able to switch between them based on market conditions and personal risk tolerance.

In our analysis, we focus exclusively on the Variable Rate mechanism.

Variable Borrow Rate

In Aave V3, the variable borrow rate (the rate paid by users who borrow assets) is dynamically adjusted based on the current utilization of the reserve.

This rate is computed inside the DefaultReserveInterestRateStrategy contract, specifically in the calculateInterestRates() function.

The logic is piecewise, depending on whether the utilization is below or above a configured threshold called the optimal usage ratio.

if (vars.borrowUsageRatio > OPTIMAL_USAGE_RATIO) {
      uint256 excessBorrowUsageRatio = (vars.borrowUsageRatio - OPTIMAL_USAGE_RATIO).rayDiv(
        MAX_EXCESS_USAGE_RATIO
      );

      vars.currentStableBorrowRate +=
        _stableRateSlope1 +
        _stableRateSlope2.rayMul(excessBorrowUsageRatio);

      vars.currentVariableBorrowRate +=
        _variableRateSlope1 +
        _variableRateSlope2.rayMul(excessBorrowUsageRatio);
    } else {
      vars.currentStableBorrowRate += _stableRateSlope1.rayMul(vars.borrowUsageRatio).rayDiv(
        OPTIMAL_USAGE_RATIO
      );

      vars.currentVariableBorrowRate += _variableRateSlope1.rayMul(vars.borrowUsageRatio).rayDiv(
        OPTIMAL_USAGE_RATIO
      );
    }

Source: DefaultReserveInterestRateStrategy.sol 

At a glance, this looks like two formulas joined together. But what does it really do?

Aave calculates how much of the lending pool is currently in use. This is called the borrow usage ratio, or simply the utilization.

Then the protocol decides how much interest to charge borrowers based on this value:

  • If utilization is low or moderate (e.g., 40% or 70% out of 100%), the borrow rate increases gradually - like a gentle slope. This makes borrowing affordable and helps the market operate normally.
  • But if utilization becomes high (goes above the optimal threshold), the rate increases much faster.

Example:

Let’s say:

  • The optimal utilization is 80%
  • The borrow rate at 80% is 4%
  • The slope after that is steep

If someone takes a large loan that pushes utilization from 80% to 90%, the borrow rate could suddenly jump from 4% to 30% or more, depending on the slope. This makes borrowing extremely expensive, which discourages further borrowing and signals that the pool is under pressure.

Mathematical model:

Let:

  • = utilization = 
    where B is the borrowed amount and L is the available liquidity.
  • = variable borrow rate
  • = base rate (a constant)
  • = slopes before and after the optimal point

= optimal usage ratio

Then:

If :

If :

r_b(U) =

Let’s now visualize this formula using a common configuration:

  • = 0.8 (i.e., 80% optimal utilization)
  • = 2%
  • = 4% (slow increase before 80%)
  • = 100% (aggressive increase after 80%)

The graph below shows how the borrow rate responds as utilization increases from 0% to 100%.

Borrow rate curve with a kink at 80% utilization.

We have now seen how the variable borrow rate is defined mathematically as a piecewise linear function. Let’s return to the relevant Solidity code mentioned above.

This if statement splits the logic exactly like our formula:

Case 1: borrowUsageRatio ≤ OPTIMAL_USAGE_RATIO

vars.currentStableBorrowRate += _stableRateSlope1.rayMul(vars.borrowUsageRatio).rayDiv(
        OPTIMAL_USAGE_RATIO
      );

      vars.currentVariableBorrowRate += _variableRateSlope1.rayMul(vars.borrowUsageRatio).rayDiv(
        OPTIMAL_USAGE_RATIO
      );

Case 2: borrowUsageRatio > OPTIMAL_USAGE_RATIO

uint256 excessBorrowUsageRatio = (vars.borrowUsageRatio - OPTIMAL_USAGE_RATIO).rayDiv(
        MAX_EXCESS_USAGE_RATIO
      );

      vars.currentStableBorrowRate +=
        _stableRateSlope1 +
        _stableRateSlope2.rayMul(excessBorrowUsageRatio);

      vars.currentVariableBorrowRate +=
        _variableRateSlope1 +
        _variableRateSlope2.rayMul(excessBorrowUsageRatio);

The Solidity implementation maps directly to the piecewise formula we discussed earlier. The use of Ray math (i.e., rayMul and rayDiv) is simply for precision; internally, all values are scaled by 1e27.

This clear correspondence between the math and the code is what makes this model both predictable and auditable, but as we’ll see in the next section, small changes in parameters can lead to extreme behaviors under certain edge conditions.

Borrow Rate Edge Cases: Sensitivity to Parameter Configuration

In this section, we simulate how a poorly chosen interest rate configuration, particularly an excessively steep , can lead to unintended consequences. Specifically, it can create a situation where the lending pool becomes effectively frozen, with no incentive for liquidity providers to deposit and no viable way for borrowers to repay.

Even well-designed interest rate models can be dangerous when misunderstood or misconfigured.

In this section, we simulate multiple edge cases that demonstrate how a single parameter change in Aave’s borrow rate model can lead to catastrophic outcomes. These examples are based on the exact mathematical model described earlier and show what happens when forks or custom deployments tamper with the parameters.

Edge Case 1: Extremely Low Optimal Utilization ()

DefaultReserveInterestRateStrategy strategy = new DefaultReserveInterestRateStrategy(
            IPoolAddressesProvider(address(this)),
            0.1e27,             // optimalUtilization = 10%
            0.02e27,            // baseRate = 2%
            0.04e27,            // slope1 = 4%
            0.5e27,             // slope2 = 50%
            0.04e27, 0.5e27, 0.01e27, 0.1e27, 0.2e27
        ); 

Config: = 10%, = 4%, = 50%, = 2%

  • Math:
    • = 10%: = 6%
    • = 50%: ≈ 28.2%
    • = 90%: ≈ 50.45%

Edge Case 2: Extremely High Optimal Utilization ()

DefaultReserveInterestRateStrategy strategy = new DefaultReserveInterestRateStrategy(
            IPoolAddressesProvider(address(this)),
            0.8e27,             // optimalUtilization = 80%
            0.02e27,            // baseRate = 2%
            0.5e27,             // slope1 = 50%
            0.1e27,             // slope2 = 10%
            0.04e27, 0.5e27, 0.01e27, 0.1e27, 0.2e27
        );

Config: = 99%, = 4%,  = 200%, = 2%

  • Math:
    • = 99%: = 6%
    • = 99.5%: ≈ 106%

Implication: The system behaves normally until it suddenly freezes. This is dangerous for high-demand assets.

Edge Case 3: Inverted Slopes ()

DefaultReserveInterestRateStrategy strategy = new DefaultReserveInterestRateStrategy(
            IPoolAddressesProvider(address(this)),
            0.8e27,             // optimalUtilization = 80%
            0.02e27,            // baseRate = 2%
            0.5e27,             // slope1 = 50%
            0.1e27,             // slope2 = 10%
            0.04e27, 0.5e27, 0.01e27, 0.1e27, 0.2e27
        );

  • Config: = 50%, = 10%, = 80%, = 2%
  • Math:
    • = 50%: = 33.25%
    • = 79%: ≈ 51.375%
    • = 90%: ≈ 57%
  • Implication: Lower borrowing cost beyond the optimal point. Incentivizes over-borrowing.

Edge Case 4: Flat Pre-Optimal Rate ()

DefaultReserveInterestRateStrategy strategy = new DefaultReserveInterestRateStrategy(
            IPoolAddressesProvider(address(this)),
            0.8e27,             // optimalUtilization = 80%
            0.02e27,            // baseRate = 2%
            0,                  // slope1 = 0%
            1e27,               // slope2 = 100%
            0.04e27, 0.5e27, 0.01e27, 0.1e27, 0.2e27
        );

  • Config:
  • Math:
    • < 80%: = 2%
    • = 90%: ≈ 52%
  • Implication: Sudden cliffs at . Users receive no warning.

Edge Case 5: Extreme Slopes

DefaultReserveInterestRateStrategy strategy = new DefaultReserveInterestRateStrategy(
            IPoolAddressesProvider(address(this)),
            0.8e27,             // optimalUtilization = 80%
            0.02e27,            // baseRate = 2%
            2e27,               // slope1 = 200%
            5e27,               // slope2 = 500%
            0.04e27, 0.5e27, 0.01e27, 0.1e27, 0.2e27
        );

  • Config:
  • Math:
    • = 10%: = 27%
    • = 50%: = 127%
    • = 90%: = 452%
  • Implication: Protocol is unsustainable even with minimal usage.

Edge Case 6: Near-Zero Optimal Utilization ()

DefaultReserveInterestRateStrategy strategy = new DefaultReserveInterestRateStrategy(
            IPoolAddressesProvider(address(this)),
            0.01e27,            // optimalUtilization = 1%
            0.02e27,            // baseRate = 2%
            0.04e27,            // slope1 = 4%
            1e27,               // slope2 = 100%
            0.04e27, 0.5e27, 0.01e27, 0.1e27, 0.2e27
        );

  • Config:
  • Math:
    • = 2%: ≈ 7.01%
    • = 50%: ≈ 55.49%
  • Implication: Pool spikes with minimal borrowing. Appears safe but punishes instantly.

Mathematically Invalid or Dangerous Configurations

Edge Case 7: Slopes > 1000%

DefaultReserveInterestRateStrategy strategy = new DefaultReserveInterestRateStrategy(
            IPoolAddressesProvider(address(this)),
            0.8e27,             // optimalUtilization = 80%
            0.02e27,            // baseRate = 2%
            10e27,              // slope1 = 1000% (Mathematically Invalid)
            50e27,              // slope2 = 5000% (Mathematically Invalid)
            0.04e27, 0.5e27, 0.01e27, 0.1e27, 0.2e27
        );

  • Config:
  • Math:
    • = 10%: = 127%
    • = 90%: = 3502%

Implication: The protocol becomes unusable almost immediately due to excessively steep rate escalation, rendering the system economically nonviable.

Edge Case 8: Base Rate = 200%

DefaultReserveInterestRateStrategy strategy = new DefaultReserveInterestRateStrategy(
            IPoolAddressesProvider(address(this)),
            0.8e27,             // optimalUtilization = 80%
            2e27,               // baseRate = 200% (Mathematically Invalid)
            0.04e27,            // slope1 = 4%
            0.5e27,             // slope2 = 50%
            0.04e27, 0.5e27, 0.01e27, 0.1e27, 0.2e27
        );

  • Config:
  • Math:
    • = 0%: = 200%
    • = 90%: = 229%

Implication: Interest accrues even when idle. The protocol is unusable.

Edge Case 9: All Parameters Extreme

  • Config:
  • Math:
    • = 10%: = 2626%
    • = 50%: = 6837%

Implication: Destructive behavior. Even minimal borrowing drives the rate into thousands of percent, instantly disincentivizing usage.

Real-World Cases of Interest Rate Parameters Configurations Issues in Aave

USDT Utilization Spike (November 2022): Aave V2’s USDT market reached over 95% utilization, creating a high risk of liquidity lock for suppliers. Governance responded with an emergency adjustment, lowering the Optimal Utilization from 90% to 80% and increasing from 60% to 75% to encourage liquidity return and reduce the likelihood of “stuck” markets.

Stablecoin Borrow Rate Adjustment (November 2024): Governance proposed raising to 9.5% for all stablecoins across Aave V3 to align borrowing rates with market conditions better. The goal was to increase protocol revenue and improve liquidity incentives, addressing imbalances caused by overly conservative initial parameters.

Conclusion

A well-audited protocol like Aave can become fragile the moment a fork changes a single value without simulating its long-tail behavior. Even minimal parameter tweaks must be reviewed as a complete system — not treated as trivial variants or narrow-scope changes. Each adjustment can propagate through interest-rate dynamics, liquidation mechanics, and user incentives, introducing systemic fragility that isn’t obvious at first glance.

Need a second set of eyes? Our security researchers can run rate-curve simulations, parameter sanity checks, and economic stress tests before you ship. Explore Hacken services →

Subscribe to our newsletter

Be the first to receive our latest company updates, Web3 security insights, and exclusive content curated for the blockchain enthusiasts.

Speaker Img