Because the wrong price is used when calculating the accruedFunding which is part of the PnL and therefore the margin of the account, the PnL is over- / underestimated which can lead to a payout to a user which is to high or to low.
The funding rate is an indicator of how much a holder of a long/ short position must pay/earns for holding the position. If the funding rate is positive, meaning that the marketPrice is above the assets price, holders of long positions need to pay a fee to holders of short positions and vice versa.
The fee is calculated based on the days the position is held. E.g. if
current fee to hold a long position is 0,15%/day
the holder of the position holds the position for 1 day
the position is 1 ETH big
the price of the asset is 3500 USD
the accumulated fees are:
0,15%/days * 1 day * 1 ETH * 3500 USD/ETH = 5,25 USD
This fee a user needs to pay/receives is calculated in getAccountMarginRequirementUsdAndUnrealizedPnlUsd
by
calculating the markPrice
depending on the change in position size (sizeDeltaX18
):
getting the current fundingRate
and using it together with the markPrice
to get the fundingFeePerUnit
:
calculate the accruedFunding for the position using the calculated fundingFeePerUnit:
From this calculation flow it is obvious that the price used to calculate the fundingFeePerUnit
directly influences the getAccruedFunding a user needs to pay / earned for holding his position.
The fee a user should pay/earn for holding a position should be the same, no matter what the “next move” of the user is, since the fees accrued in the “past”.
The problem is that the price which is used to calculate the fundingFeePerUnit
and therefore the getAccruedFunding
is the markPrice
which depends on the size and direction of the position currently changed. This is because markPrice
is an average of the price before the trade and after the trade:
This results in different fees to pay for the user depending on the size of the position and its direction.
Example:
User has an existing position with the size of 500 ETH. He held the position for 1 day and wants to close it fully and will thereby reduce the scew of the market. The lastInteractionFundingFeePerUnit
for the position is 0 (for simplicity).
User values
:
Size Existing: 500 ETH
lastInteractionFundingFeePerUnit: 0 (for simplicity)
Position duration: 1 day
Next Action: close the position
The market currently has a scew of 500, a scewSale of 10,000 and the currentFundingRate
0,15%/day and the lastFundingFeePerUnit is 0 (for simplicity):
Values of the market
:
Scew: 500
scewScale: 10,000
currentFundingRate: 0,15%/day
lastFundingFeePerUnit: 0 (for simplicity)
The current oracle price is 3,500 USD/ETH. Including the scew of the market, the markPrice before closing the position is 3,675 USD/ETH:
Therefore the fundingFeePerUnit
using the currentFundingRate
and the priceBeforeDelta
is 2,76USD/ ETH:
This results in accumulatedFunding
for the 500 Eth position of 1380 USD.
But since the current implementation uses the markPrice
which is the average of priceImpactBeforeDelta
and priceImpactAfterDelta
, closing the 500 Eth position result in a makrPrice of 3587,5 USD/ETH instead of 3,675 USD/ETH:
Therefore the fundingFeePerUnit
using the currentFundingRate
and the priceBeforeDelta
is 2,69USD/ ETH:
This results in accumulatedFunding
for the 10 Eth position of 1345 USD instead of 1380 USD.
Use the price before the trade (priceBeforeDelta
) to calculate the fees a user needs to pay for holding a position. This way the calculated fees are the fees accrued since the last interaction with the position and are not influenced by the change in position a user is making.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.