5/5
## Understanding Borrowing Fees in Decentralized Trading In the world of decentralized finance (DeFi), particularly on trading platforms like perpetual exchanges, the concept of a "Borrowing Fee" is fundamental. This lesson explores what this fee entails, why it exists, and how it's calculated efficiently on the blockchain. **What is a Borrowing Fee?** A Borrowing Fee is a charge paid by a trader who has an open position on a platform to the liquidity providers (LPs) who supply the assets enabling that trade. When a trader opens a long or short position, they are effectively borrowing assets or liquidity from a pool funded by LPs. The borrowing fee compensates these LPs for making their capital available. While the fee accrues continuously for the entire duration a position remains open, it is typically calculated and settled when the trader closes their position. It represents the cost of leveraging the platform's liquidity over time. **The Purpose of Borrowing Fees** Borrowing fees serve two primary purposes: 1. **Incentivize Liquidity Providers:** LPs take on risk by depositing their assets into liquidity pools. Borrowing fees provide them with a revenue stream, compensating them for this risk and the opportunity cost of their capital, thereby encouraging participation and deepening platform liquidity. 2. **Incentivize Traders:** The fee discourages traders from keeping positions (especially unprofitable ones) open indefinitely. Without this cost, capital could remain locked in positions for extended periods, reducing liquidity availability for others. The fee adds a time-based cost, encouraging efficient capital management and position closure. **Key Factors in Borrowing Fee Calculation** Several elements determine the total borrowing fee: * **Position Size (C):** The value or size of the trader's open position. A larger position naturally incurs a larger fee, all else being equal. * **Borrowing Rate (R_i):** This is the rate at which the fee accrues, often expressed per unit of position size per second (or another small time unit). Crucially, this rate is *not* constant. It fluctuates based on market conditions, primarily the utilization of the liquidity pool (how much of the available liquidity is being borrowed). Higher utilization typically leads to a higher borrowing rate. Think of this rate `R_i` applying during a specific time interval, like from second `i` to second `i+1`. * **Duration:** The length of time the position remains open, from the opening time (`k`) to the closing time (`N`). The fundamental relationship is: Borrowing Fee depends on Position Size, the fluctuating Borrowing Rate, and the Duration the position is held. **Calculating the Fee: The Naive Approach** The most straightforward way to think about calculating the fee is to sum up the small amounts accrued during each time interval the position is open. If a user `u` opens a position at time `k` and closes it at time `N`, and their position size at any given time `i` is `S_u,i`, while the borrowing rate during the interval `[i, i+1)` is `R_i`, the total fee could be calculated as: `Borrowing Fee = Σ[i=k to N-1] (S_u,i * R_i)` This formula represents the sum (Σ) of the fees accrued in each second (or time interval `i`) from the opening time `k` up to (but not including) the closing time `N`. The fee in each interval is the position size at that moment (`S_u,i`) multiplied by the borrowing rate for that interval (`R_i`). **The Problem with the Naive Approach on Blockchains** While mathematically simple, implementing this naive calculation directly within a smart contract is highly impractical. Why? Because the borrowing rate `R_i` can change frequently based on market activity. Every time `R_i` changes, or at every regular time step, the smart contract would potentially need to: 1. Identify *all* currently open positions across *all users*. 2. Calculate the incremental fee (`S_u,i * R_i`) for each position. 3. Update an stored accrued fee value for each position. Performing these operations for potentially thousands of users and positions in a loop within a single transaction would consume an enormous amount of computational resources (gas) on the blockchain, making the process prohibitively expensive and slow. **An Efficient Calculation: The Cumulative Sum Method (Used by GMX)** To overcome the gas cost limitations, protocols like GMX employ a more efficient method based on mathematical simplification, which works particularly well when the **position size (C) remains constant** from opening to closing. Here's the insight: 1. Start with the naive sum, assuming a constant position size `C`: `Fee = C*R_k + C*R_{k+1} + ... + C*R_{N-1}` 2. Factor out the constant position size `C`: `Fee = C * (R_k + R_{k+1} + ... + R_{N-1})` 3. The core trick is to express the sum of rates `(R_k + ... + R_{N-1})` using *cumulative sums*. Imagine the protocol maintains a running total of all borrowing rates from the very beginning (time `t=0`). Let `CumulativeRateSum(t) = Σ[i=0 to t] R_i`. 4. The sum of rates *during* the position's lifetime can be found by taking the cumulative sum up to the closing time and subtracting the cumulative sum up to the opening time: `(R_k + ... + R_{N-1}) = (R_0 + ... + R_{N-1}) - (R_0 + ... + R_{k-1})` 5. Substituting this back into the fee equation gives the simplified formula: `Borrowing Fee = C * ( Σ[i=0 to N-1] R_i - Σ[i=0 to k-1] R_i )` **How This Simplification Achieves Efficiency:** * **Single Global State:** The smart contract only needs to maintain *one* primary global variable related to borrowing fees: the cumulative sum of all borrowing rates since deployment (`Σ R_i`). This variable is updated only when the borrowing rate `R_i` itself changes. * **At Position Open:** When a user opens a position of size `C` at time `k`, the smart contract simply reads the *current* global cumulative rate sum (`Σ[i=0 to k-1] R_i`) and stores this value specifically for that user's position. * **At Position Close:** When the user closes the position at time `N`, the smart contract reads the *new* current global cumulative rate sum (`Σ[i=0 to N-1] R_i`). * **Final Calculation:** The contract calculates the difference between the cumulative sum at close and the stored cumulative sum from open (`Σ[i=0 to N-1] R_i - Σ[i=0 to k-1] R_i`). This difference represents the sum of rates during the position's lifetime. It then multiplies this difference by the constant position size `C` to get the final borrowing fee. This approach avoids any loops over users or positions during rate updates or fee calculations, drastically reducing gas costs and making the system viable on-chain. **Illustrative Example:** Consider Alice opens a position: * Constant Position Size `C` = 100 units. * Opens at time `t=2` (so index `k=2`). * Closes at time `t=5` (so index `N=5`). The relevant rates are `R2`, `R3`, `R4` (covering intervals [2,3), [3,4), [4,5)). Using the efficient method: 1. At `t=2` (open), the contract records the cumulative sum up to `k-1=1`: `Sum_Open = Σ[i=0 to 1] R_i = R0 + R1`. 2. At `t=5` (close), the contract reads the current cumulative sum up to `N-1=4`: `Sum_Close = Σ[i=0 to 4] R_i = R0 + R1 + R2 + R3 + R4`. 3. The fee is calculated as: `Fee = C * (Sum_Close - Sum_Open)` `Fee = 100 * ( (R0 + R1 + R2 + R3 + R4) - (R0 + R1) )` `Fee = 100 * (R2 + R3 + R4)` This matches the intuitive sum but was calculated using only two lookups of the global cumulative sum and one subtraction, regardless of how many rate changes occurred or how many other users had positions open. **Key Considerations** * The cumulative sum method provides a massive gas efficiency gain over naive summation, making borrowing fees practical for smart contracts. * The simplification presented here relies heavily on the **position size `C` remaining constant**. If a user adds to or partially closes their position, the calculation becomes more complex, typically requiring the fee accrued up to that point to be settled or accounted for before applying the method to the adjusted position size going forward. * This efficient approach is a common pattern in DeFi, notably used by protocols like GMX for their borrowing/funding rate mechanisms.
In the world of decentralized finance (DeFi), particularly on trading platforms like perpetual exchanges, the concept of a "Borrowing Fee" is fundamental. This lesson explores what this fee entails, why it exists, and how it's calculated efficiently on the blockchain.
What is a Borrowing Fee?
A Borrowing Fee is a charge paid by a trader who has an open position on a platform to the liquidity providers (LPs) who supply the assets enabling that trade. When a trader opens a long or short position, they are effectively borrowing assets or liquidity from a pool funded by LPs. The borrowing fee compensates these LPs for making their capital available.
While the fee accrues continuously for the entire duration a position remains open, it is typically calculated and settled when the trader closes their position. It represents the cost of leveraging the platform's liquidity over time.
The Purpose of Borrowing Fees
Borrowing fees serve two primary purposes:
Incentivize Liquidity Providers: LPs take on risk by depositing their assets into liquidity pools. Borrowing fees provide them with a revenue stream, compensating them for this risk and the opportunity cost of their capital, thereby encouraging participation and deepening platform liquidity.
Incentivize Traders: The fee discourages traders from keeping positions (especially unprofitable ones) open indefinitely. Without this cost, capital could remain locked in positions for extended periods, reducing liquidity availability for others. The fee adds a time-based cost, encouraging efficient capital management and position closure.
Key Factors in Borrowing Fee Calculation
Several elements determine the total borrowing fee:
Position Size (C): The value or size of the trader's open position. A larger position naturally incurs a larger fee, all else being equal.
Borrowing Rate (R_i): This is the rate at which the fee accrues, often expressed per unit of position size per second (or another small time unit). Crucially, this rate is not constant. It fluctuates based on market conditions, primarily the utilization of the liquidity pool (how much of the available liquidity is being borrowed). Higher utilization typically leads to a higher borrowing rate. Think of this rate R_i
applying during a specific time interval, like from second i
to second i+1
.
Duration: The length of time the position remains open, from the opening time (k
) to the closing time (N
).
The fundamental relationship is: Borrowing Fee depends on Position Size, the fluctuating Borrowing Rate, and the Duration the position is held.
Calculating the Fee: The Naive Approach
The most straightforward way to think about calculating the fee is to sum up the small amounts accrued during each time interval the position is open.
If a user u
opens a position at time k
and closes it at time N
, and their position size at any given time i
is S_u,i
, while the borrowing rate during the interval [i, i+1)
is R_i
, the total fee could be calculated as:
Borrowing Fee = Σ[i=k to N-1] (S_u,i * R_i)
This formula represents the sum (Σ) of the fees accrued in each second (or time interval i
) from the opening time k
up to (but not including) the closing time N
. The fee in each interval is the position size at that moment (S_u,i
) multiplied by the borrowing rate for that interval (R_i
).
The Problem with the Naive Approach on Blockchains
While mathematically simple, implementing this naive calculation directly within a smart contract is highly impractical. Why? Because the borrowing rate R_i
can change frequently based on market activity. Every time R_i
changes, or at every regular time step, the smart contract would potentially need to:
Identify all currently open positions across all users.
Calculate the incremental fee (S_u,i * R_i
) for each position.
Update an stored accrued fee value for each position.
Performing these operations for potentially thousands of users and positions in a loop within a single transaction would consume an enormous amount of computational resources (gas) on the blockchain, making the process prohibitively expensive and slow.
An Efficient Calculation: The Cumulative Sum Method (Used by GMX)
To overcome the gas cost limitations, protocols like GMX employ a more efficient method based on mathematical simplification, which works particularly well when the position size (C) remains constant from opening to closing.
Here's the insight:
Start with the naive sum, assuming a constant position size C
:
Fee = C*R_k + C*R_{k+1} + ... + C*R_{N-1}
Factor out the constant position size C
:
Fee = C * (R_k + R_{k+1} + ... + R_{N-1})
The core trick is to express the sum of rates (R_k + ... + R_{N-1})
using cumulative sums. Imagine the protocol maintains a running total of all borrowing rates from the very beginning (time t=0
). Let CumulativeRateSum(t) = Σ[i=0 to t] R_i
.
The sum of rates during the position's lifetime can be found by taking the cumulative sum up to the closing time and subtracting the cumulative sum up to the opening time:
(R_k + ... + R_{N-1}) = (R_0 + ... + R_{N-1}) - (R_0 + ... + R_{k-1})
Substituting this back into the fee equation gives the simplified formula:
Borrowing Fee = C * ( Σ[i=0 to N-1] R_i - Σ[i=0 to k-1] R_i )
How This Simplification Achieves Efficiency:
Single Global State: The smart contract only needs to maintain one primary global variable related to borrowing fees: the cumulative sum of all borrowing rates since deployment (Σ R_i
). This variable is updated only when the borrowing rate R_i
itself changes.
At Position Open: When a user opens a position of size C
at time k
, the smart contract simply reads the current global cumulative rate sum (Σ[i=0 to k-1] R_i
) and stores this value specifically for that user's position.
At Position Close: When the user closes the position at time N
, the smart contract reads the new current global cumulative rate sum (Σ[i=0 to N-1] R_i
).
Final Calculation: The contract calculates the difference between the cumulative sum at close and the stored cumulative sum from open (Σ[i=0 to N-1] R_i - Σ[i=0 to k-1] R_i
). This difference represents the sum of rates during the position's lifetime. It then multiplies this difference by the constant position size C
to get the final borrowing fee.
This approach avoids any loops over users or positions during rate updates or fee calculations, drastically reducing gas costs and making the system viable on-chain.
Illustrative Example:
Consider Alice opens a position:
Constant Position Size C
= 100 units.
Opens at time t=2
(so index k=2
).
Closes at time t=5
(so index N=5
).
The relevant rates are R2
, R3
, R4
(covering intervals [2,3), [3,4), [4,5)).
Using the efficient method:
At t=2
(open), the contract records the cumulative sum up to k-1=1
: Sum_Open = Σ[i=0 to 1] R_i = R0 + R1
.
At t=5
(close), the contract reads the current cumulative sum up to N-1=4
: Sum_Close = Σ[i=0 to 4] R_i = R0 + R1 + R2 + R3 + R4
.
The fee is calculated as:
Fee = C * (Sum_Close - Sum_Open)
Fee = 100 * ( (R0 + R1 + R2 + R3 + R4) - (R0 + R1) )
Fee = 100 * (R2 + R3 + R4)
This matches the intuitive sum but was calculated using only two lookups of the global cumulative sum and one subtraction, regardless of how many rate changes occurred or how many other users had positions open.
Key Considerations
The cumulative sum method provides a massive gas efficiency gain over naive summation, making borrowing fees practical for smart contracts.
The simplification presented here relies heavily on the position size C
remaining constant. If a user adds to or partially closes their position, the calculation becomes more complex, typically requiring the fee accrued up to that point to be settled or accounted for before applying the method to the adjusted position size going forward.
This efficient approach is a common pattern in DeFi, notably used by protocols like GMX for their borrowing/funding rate mechanisms.
An essential breakdown of Borrowing Fees - Learn why traders pay borrowing fees and how these incentivize liquidity providers. Discover the efficient cumulative sum technique used by protocols like GMX to overcome on-chain gas limitations.
Previous lesson
Previous
Next lesson
Next
Give us feedback
Cyfrin Updraft has partnered with GMX to provide SSCD+ certifications vouchers to the first 25 students who demonstrate the completion of this course and are building on top of GMX. Join the GMX Discord server to redeem your coupon, or navigate to the docs to learn more!
Course Overview
About the course
Mechanics and contract architecture of the GMX protocol
Token pricing and fees
Liquidity: GM pools and GLV vaults
Math, funding rates, liquidation pricing, P&L calculations
Limit orders, take profit orders, stop loss, and stop market orders
Auto-cancel and auto-deleveraging
GLP, esGMX, GMX staking and delegation
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Last updated on June 26, 2025
Duration: 8min
Duration: 1h 19min
Duration: 1h 24min
Duration: 16min
Duration: 11min
Duration: 11min
Duration: 6min
Course Overview
About the course
Mechanics and contract architecture of the GMX protocol
Token pricing and fees
Liquidity: GM pools and GLV vaults
Math, funding rates, liquidation pricing, P&L calculations
Limit orders, take profit orders, stop loss, and stop market orders
Auto-cancel and auto-deleveraging
GLP, esGMX, GMX staking and delegation
DeFi Developer
$75,000 - $200,000 (avg. salary)
Smart Contract Engineer
$100,000 - $150,000 (avg. salary)
Web3 developer
$60,000 - $150,000 (avg. salary)
Web3 Developer Relations
$85,000 - $125,000 (avg. salary)
Smart Contract Auditor
$100,000 - $200,000 (avg. salary)
Security researcher
$49,999 - $120,000 (avg. salary)
Last updated on June 26, 2025