Summary
When a new position is created, its funding will always be 0 and the entire calculation is unnecessary.
Vulnerability Details
Every time TradingAccount.getAccountMarginRequirementUsdAndUnrealizedPnlUsd()
is called, it calculates the position data, but the funding of a new position will always be 0, so there are unnecessary calculations with 0 amounts.
fundingFeePerUnit
will be 0 then this will be multiplied by position.size
inside getAccruedFunding()
.
function getAccountMarginRequirementUsdAndUnrealizedPnlUsd(
Data storage self,
uint128 targetMarketId,
SD59x18 sizeDeltaX18
)
internal
view
returns (
UD60x18 requiredInitialMarginUsdX18,
UD60x18 requiredMaintenanceMarginUsdX18,
SD59x18 accountTotalUnrealizedPnlUsdX18
)
{
if (targetMarketId != 0) {
PerpMarket.Data storage perpMarket = PerpMarket.load(targetMarketId);
Position.Data storage position = Position.load(self.id, targetMarketId);
UD60x18 markPrice = perpMarket.getMarkPrice(sizeDeltaX18, perpMarket.getIndexPrice());
SD59x18 fundingFeePerUnit =
perpMarket.getNextFundingFeePerUnit(perpMarket.getCurrentFundingRate(), markPrice);
UD60x18 notionalValueX18 = sd59x18(position.size).add(sizeDeltaX18).abs().intoUD60x18().mul(markPrice);
(UD60x18 positionInitialMarginUsdX18, UD60x18 positionMaintenanceMarginUsdX18) = Position
.getMarginRequirement(
notionalValueX18,
ud60x18(perpMarket.configuration.initialMarginRateX18),
ud60x18(perpMarket.configuration.maintenanceMarginRateX18)
);
SD59x18 positionUnrealizedPnl =
position.getUnrealizedPnl(markPrice).add(position.getAccruedFunding(fundingFeePerUnit));
requiredInitialMarginUsdX18 = requiredInitialMarginUsdX18.add(positionInitialMarginUsdX18);
requiredMaintenanceMarginUsdX18 = requiredMaintenanceMarginUsdX18.add(positionMaintenanceMarginUsdX18);
accountTotalUnrealizedPnlUsdX18 = accountTotalUnrealizedPnlUsdX18.add(positionUnrealizedPnl);
}
... MORE CODE
function getAccruedFunding(
Data storage self,
SD59x18 fundingFeePerUnit
)
internal
view
returns (SD59x18 accruedFundingUsdX18)
{
SD59x18 netFundingFeePerUnit = fundingFeePerUnit.sub(sd59x18(self.lastInteractionFundingFeePerUnit));
accruedFundingUsdX18 = sd59x18(self.size).mul(netFundingFeePerUnit);
}
Impact
Unnecessary calculations for funding, which is always 0.
Tools Used
Manual Review
Recommendations
In all these cases, check if lastInteractionFundingFeePerUnit = 0
and if so, return 0 for funding, skipping all these calculations.