Summary
PremiumDiscountFactor
feature is not working in the protocol.
Vulnerability Details
Protocol uses PremiumDiscountFactor
to calculate assets amountOut
during the swap in Market Making Engine, however, it was observed that there is no way to initialize few state variables that UsdTokenSwapConfig.sol:getPremiumDiscountFactor() function uses: pdCurveYMin
, pdCurveYMax
, pdCurveXMin
, pdCurveXMax
, pdCurveZ
, as a result premiumDiscountFactor
always will be equal to UD60x18_UNIT
.
function getPremiumDiscountFactor(
Data storage self,
UD60x18 vaultAssetsValueUsdX18,
SD59x18 vaultDebtUsdX18
)
internal
view
returns (UD60x18 premiumDiscountFactorX18)
{
UD60x18 vaultDebtTvlRatioAbs = vaultDebtUsdX18.abs().intoUD60x18().div(vaultAssetsValueUsdX18);
UD60x18 pdCurveXMinX18 = ud60x18(self.pdCurveXMin);
UD60x18 pdCurveXMaxX18 = ud60x18(self.pdCurveXMax);
if (vaultDebtTvlRatioAbs.lte(pdCurveXMinX18)) {
premiumDiscountFactorX18 = UD60x18_UNIT;
return premiumDiscountFactorX18;
}
UD60x18 pdCurveXX18 = vaultDebtTvlRatioAbs.gte(pdCurveXMaxX18) ? pdCurveXMaxX18 : vaultDebtTvlRatioAbs;
UD60x18 pdCurveYMinX18 = ud60x18(self.pdCurveYMin);
UD60x18 pdCurveYMaxX18 = ud60x18(self.pdCurveYMax);
UD60x18 pdCurveZX18 = ud60x18(self.pdCurveZ);
UD60x18 pdCurveYX18 = pdCurveYMinX18.add(
pdCurveYMaxX18.sub(pdCurveYMinX18).mul(
pdCurveXX18.sub(pdCurveXMinX18).div(pdCurveXMaxX18.sub(pdCurveXMinX18)).pow(pdCurveZX18)
)
);
premiumDiscountFactorX18 =
vaultDebtUsdX18.lt(SD59x18_ZERO) ? UD60x18_UNIT.sub(pdCurveYX18) : UD60x18_UNIT.add(pdCurveYX18);
}
By description in the comments to the code:
But premiumDiscountFactor
always will be equal to UD60x18_UNIT
.
Impact
premiumDiscountFactor
always will be equal to UD60x18_UNIT
no matter if vault is in credit or not.
Tools Used
Manual Review
Recommendations
Update MarketMakingEngineConfiguration.sol:configureUsdTokenSwapConfig():
function configureUsdTokenSwapConfig(
uint128 baseFeeUsd,
uint128 swapSettlementFeeBps,
uint128 maxExecutionTime,
+ uint128 pdCurveYMin,
+ uint128 pdCurveYMax,
+ uint128 pdCurveXMin,
+ uint128 pdCurveXMax,
+ uint128 pdCurveZ
)
external
onlyOwner
{
if (maxExecutionTime == 0) {
revert Errors.ZeroInput("maxExecutionTime");
}
// emits event internally
UsdTokenSwapConfig.update(
baseFeeUsd,
swapSettlementFeeBps,
maxExecutionTime,
+ pdCurveYMin,
+ pdCurveYMax,
+ pdCurveXMin,
+ pdCurveXMax,
+ pdCurveZ
);
}
And UsdTokenSwapConfig.sol:update():
function update(
uint128 baseFeeUsd,
uint128 swapSettlementFeeBps,
uint128 maxExecutionTime,
+ uint128 pdCurveYMin,
+ uint128 pdCurveYMax,
+ uint128 pdCurveXMin,
+ uint128 pdCurveXMax,
+ uint128 pdCurveZ
) internal {
Data storage self = load();
self.baseFeeUsd = baseFeeUsd;
self.swapSettlementFeeBps = swapSettlementFeeBps;
self.maxExecutionTime = maxExecutionTime;
+ self.pdCurveYMin = pdCurveYMin;
+ self.pdCurveYMax = pdCurveYMax;
+ self.pdCurveXMin = pdCurveXMin;
+ self.pdCurveXMax = pdCurveXMax;
+ self.pdCurveZ = pdCurveZ;
emit LogUpdateUsdTokenSwapConfig(baseFeeUsd, swapSettlementFeeBps, maxExecutionTime);
}