Borrowing Fee

Takers pay borrowing fees similar to interest paid to borrow tokens on lending platforms and it based on the utilization ratio of makers in that market.

  • In general, takers pay borrowing fees for all open positions.

  • Maker (LP) positions generally receive a borrowing fee, and pay the fee in some instances.

  • Borrowing fees are pending until settlement by the Vault when certain events occur.

  • A positive fee is one that is payed; a negative fee is one that is received (earned).

  • Borrowing fees are paid directly to/from the position margin, thus affecting margin ratio over time.

Overview

Borrowing fees are initially pending fees, and can be settled by calling _settleBorrowingFee.

Definitions

  • Long and short states are separate and independent.

  • Receiver: a user that earns borrowing fees: generally a subset of makers; cannot increase position proactively; cannot censor orders in any circumstances.

  • Payer: a user that pays borrowing fees; any user that is not a receiver is a payer.

  • Takers can only be payers; makers/LPs can be either payer or receiver.

Utilization Ratio

utilizationRatio:={Min(1,Abs(openNotional)margin)if margin > 01if margin <=0utilizationRatio := \begin{cases} Min(1, \cfrac{Abs(openNotional)}{margin}) &\text{if margin > 0} \\ 1 &\text{if margin <=0} \end{cases}

Borrowing fee calculation

A trader can have one or two roles

  • Maker: trader who guarantees to provide passive liquidity

  • Taker: trader who takes that liquidity

If a certain type of maker qualifies as a receiver, the system will compensate the maker with borrowing fees paid by takers.

borrowingFeeRate per second = abs(openNotional) * utilRatio * maxBorrowingFeeRate

Borrowing fees for long and short positions are separate. Unlike traditional funding rates based on position size, borrowing fee rates are based on open notional. Example:

maxBorrowingFeeRate = 10%
utilRatio = 50%
// Assume there's only one receiver (maker)
margin notional = 2
// A trader opens a long
position notional = 1
// The trader's borrowing fee rate will be:
borrowingFeeRate = abs(-1) * 0.5 * 0.1 = 0.05 = 5%

Whitelisted Maker

  • Receives borrowing fees based on their utilization ratio

  • Does not pay borrowing fees

Whitelist Criteria

  • Maker must fill any order received. Notes:

    1. The only way we can think of that can guarantee is to whitelist smart contract controlled by DAO, and the pricing mechanism has no off-chain component

    2. Other than that there’s no perfect way to guarantee this on-chain. bad actor can accept order in a ridiculous price if she does not want to accept the order. restricting a price range may help but still not good enough

  • Maker cannot increase position actively. Notes:

    1. This limitation is needed to prevent whitelisted makers from gaming borrowing fees.

    2. Can reduce position actively, which gives the maker some characteristics of a taker.

  • Maker must have no position initially.

  • The Perpetual DAO is charged with adding/removing makers from whitelist.

Non-Whitelisted Maker

Non-whitelisted maker feature will be activated after launch.

Accounts that are not a whitelisted maker will earn, and may also pay borrowing fees.

  • No restrictions on what orders may be filled / not filled

  • Examples

    • The party acting as the maker in the off-chain order book.

    • Other unofficially maintained private makers. (Not open to private makers for now)

Contract

struct SettleBorrowingFeeParams {
    uint256 marketId;
    address trader;
    int256 positionSizeDelta;
    int256 openNotionalDelta;
}
function getPendingFee(
    uint256 marketId, 
    address trader
)

/// @notice For payer (liquidity consumer)
return int256 payerBorrowingFee;

/// @notice For receiver (liquidity provider)
return int256 receiverBorrowingFee;
/// @dev Additional contract functions
/// @notice Query market max borrowing fee
function getMaxBorrowingFeeRate(
    uint256 marketId
)
returns (
    uint256, // MaxBorrowingFeeRate
    uint256 // marketId
) 

/// @notice Query total open notional held by receivers
function getTotalReceiverOpenNotional(
    uint256 marketId
) 
returns (
    uint256, // TotalReceiverOpenNotional
    uint256 // marketId
)

/// @notice Query total open notional held by payers
function getTotalPayerOpenNotional(
    uint256 marketId
)
returns (
    uint256, // TotalPayerOpenNotional
    uint256 // marketId
)

/// @dev getUtilRatio has moved to the individual maker contracts
function getUtilRatio

Last updated