Skip to content

Latest commit

 

History

History
188 lines (135 loc) · 6.55 KB

File metadata and controls

188 lines (135 loc) · 6.55 KB

Borrowing fee

  • Paid from position holder (trader) to liquidity provider.
  • Discourages a user opening equal longs / shorts and unnecessarily taking up capacity

How is borrowing fee calculated for trader?

MarketUtils.getBorrowingFees

How is borrowing fee updated for trader?

Increase or decrease in position increases pool amount

MarketUtils.updateCumulativeBorrowingFactor

ExecuteOrderUtils.executeOrder
├ PositionUtils.updateFundingAndBorrowingState
└ processOrder
    └ IncreaseOrderUtils.processOrder
        └ IncreasePositionUtils.increasePosition
            ├ processCollateral
            │   ├ PositionPricingUtils.getPositionFees
            │   │  └ MarketUtils.getBorrowingFees
            │   └ MarketUtils.applyDeltaToPoolAmount
            ├ params.position.setCollateralAmount
            ├ MarketUtils.getCumulativeBorrowingFactor
            ├ PositionUtils.updateTotalBorrowing
            └ params.position.setBorrowingFactor
ExecuteOrderUtils.executeOrder
├ PositionUtils.updateFundingAndBorrowingState
└ processOrder
    └ DecreaseOrderUtils.processOrder
        └ DecreasePositionUtils.decreasePosition
            ├ DecreasePositionCollateralUtils.processCollateral
            │   ├ PositionPricingUtils.getPositionFees
            │   │  └ MarketUtils.getBorrowingFees
            │   └ MarketUtils.applyDeltaToPoolAmount
            ├ MarketUtils.getCumulativeBorrowingFactor
            ├ PositionUtils.updateTotalBorrowing
            ├ params.position.setBorrowingFactor
            └ params.position.setCollateralAmount

How is borrowing fee rate calculated?

MarketUtils.updateCumulativeBorrowingFactor

MarketUtils.getBorrowingFactorPerSecond

PositionUtils.updateFundingAndBorrowingState
└ MarketUtils.updateCumulativeBorrowingFactor
    ├ getNextCumulativeBorrowingFactor
    │    ├ getSecondsSinceCumulativeBorrowingFactorUpdated
    │    ├ getBorrowingFactorPerSecond
    │    │  ├ getOptimalUsageFactor
    │    │  ├ if optimal usage factor != 0
    │    │  │  └ getKinkBorrowingFactor
    │    │  │      └ getUsageFactor
    │    │  ├ getBorrowingExponentFactor
    │    │  └ getBorrowingFactor
    │    └ getCumulativeBorrowingFactor
    └ incrementCumulativeBorrowingFactor
if optimal usage factor = 0
    e = borrowing exponent factor
    r = reserve USD
    P = pool USD
    b = borrowing factor
    r^e / P * b

MarketUtils.getReservedUsd

MarketUtils.getUsageFactor

usage factor = max(reserve usage factor, open interest usage factor)
reserve usage factor = reserved USD / max reserve
max reserve = reserve factor * pool usd
open interest usage factor = open interest / max open interest

MarketUtils.getKinkBorrowingFactor

u = usage factor
u_o = optimal usage factor
b0 = base borrowing factor
b1 = above optimal usage borrowing factor

kink borrowing factor per second = b0 * u

if u > u_o
    kink borrowing factor per second += max(b1 - b0, 0) * (u - u_o) / (1 - u_o)

GMX Synthetics uses a kinked borrowing rate model (like Compound & Aave) to dynamically adjust costs based on utilization. It’s linear up to a threshold, then sharply exponential/linear beyond, ensuring liquidity safety and discouraging unhealthy leverage.

📝 Note on getKinkBorrowingFactor

The function implements a kinked borrowing rate model for GMX Synthetics. It determines the borrowing factor per second for a given market (long or short) based on pool utilization.


🔹 1. Usage Factor

uint256 usageFactor = getUsageFactor(...);

The usage factor ( u ) is defined as the ratio of reserved liquidity to available pool liquidity:

$$u = \frac{\text{reservedUsd}}{\text{poolUsd}}$$

scaled by a fixed precision constant (Precision.FLOAT_PRECISION).


🔹 2. Base Borrowing Factor

uint256 baseBorrowingFactor = dataStore.getUint(Keys.baseBorrowingFactorKey(...));
uint256 borrowingFactorPerSecond = Precision.applyFactor(usageFactor, baseBorrowingFactor);

Below the optimal utilization, the borrowing factor per second grows linearly with usage:

$$b(u) = b_0 \cdot u, \quad \text{for } u \leq u_o$$

where:

  • ( b_0 ) = base borrowing factor
  • ( u ) = usage factor
  • ( u_o ) = optimal usage factor (the kink point)

🔹 3. Above Optimal Usage (Kink Penalty)

If utilization exceeds the optimal usage factor, an additional penalty is applied:

if (usageFactor > optimalUsageFactor) {
    uint256 diff = usageFactor - optimalUsageFactor;
    uint256 aboveOptimalUsageBorrowingFactor = dataStore.getUint(...);
    uint256 additionalBorrowingFactorPerSecond = aboveOptimalUsageBorrowingFactor - baseBorrowingFactor;
    uint256 divisor = Precision.FLOAT_PRECISION - optimalUsageFactor;

    borrowingFactorPerSecond += additionalBorrowingFactorPerSecond * diff / divisor;
}

This corresponds to:

$$b(u) = b_0 \cdot u + \big(b_1 - b_0\big) \cdot \frac{u - u_o}{1 - u_o}, \quad \text{for } u > u_o$$

where:

  • ( b_1 ) = above-optimal usage borrowing factor
  • ( b_1 > b_0 ) ensures a steeper slope after the kink

🔹 4. Final Piecewise Formula

Putting it all together:

$$b(u) = \begin{cases} b_0 \cdot u, & u \leq u_o \[6pt] b_0 \cdot u + (b_1 - b_0) \cdot \dfrac{u - u_o}{1 - u_o}, & u > u_o \end{cases}$$


Summary: The function enforces a linear borrowing rate below the kink, and a sharply increasing rate beyond the kink. This discourages excessive pool utilization, protecting liquidity providers while maintaining efficient capital use.

How is borrowing claimed by LP?

Claimed from increased pool amount