Summary
The createPerpMarket()
and updatePerpMarketConfiguration()
functions passes the priceFeedHeartbeatSeconds
parameter, but the MarketConfiguration::update()
function does not utilize it, leading to an incomplete market configuration update.
Vulnerability Details
createPerpMarket()
calls PerpMarket::create()
to set the configuration variables of the given perp market id.
Within it, it calls MarketConfiguration::update()
as follows:
self.configuration.update(
MarketConfiguration.Data({
name: params.name,
symbol: params.symbol,
priceAdapter: params.priceAdapter,
initialMarginRateX18: params.initialMarginRateX18,
maintenanceMarginRateX18: params.maintenanceMarginRateX18,
maxOpenInterest: params.maxOpenInterest,
maxSkew: params.maxSkew,
maxFundingVelocity: params.maxFundingVelocity,
minTradeSizeX18: params.minTradeSizeX18,
skewScale: params.skewScale,
orderFees: params.orderFees,
>> priceFeedHeartbeatSeconds: params.priceFeedHeartbeatSeconds
})
);
However, the MarketConfiguration::update()
function does not utilize the priceFeedHeartbeatSeconds
provided above:
function update(Data storage self, Data memory params) internal {
self.name = params.name;
self.symbol = params.symbol;
self.priceAdapter = params.priceAdapter;
self.initialMarginRateX18 = params.initialMarginRateX18;
self.maintenanceMarginRateX18 = params.maintenanceMarginRateX18;
self.maxOpenInterest = params.maxOpenInterest;
self.maxSkew = params.maxSkew;
self.maxFundingVelocity = params.maxFundingVelocity;
self.minTradeSizeX18 = params.minTradeSizeX18;
self.skewScale = params.skewScale;
self.orderFees = params.orderFees;
>>
}
Issue:
The priceFeedHeartbeatSeconds
parameter is passed but not set in MarketConfiguration::update()
. This same issue persists in updatePerpMarketConfiguration()
Impact
The priceFeedHeartbeatSeconds
remains unset i.e 0
, leading to potential inconsistencies in the market configuration.
Setting the oracle heartbeat to 0
effectively disables the time-based validation of oracle updates.
---> Code will execute with prices that don’t reflect the current pricing. Decisions based on stale data can result in incorrect pricing, margin calculations, and liquidations, causing financial losses to users and the platform.
Tools Used
Manual Review
Recommendations
Modify the MarketConfiguration::update()
function to include the priceFeedHeartbeatSeconds
parameter:
function update(Data storage self, Data memory params) internal {
self.name = params.name;
self.symbol = params.symbol;
self.priceAdapter = params.priceAdapter;
self.initialMarginRateX18 = params.initialMarginRateX18;
self.maintenanceMarginRateX18 = params.maintenanceMarginRateX18;
self.maxOpenInterest = params.maxOpenInterest;
self.maxSkew = params.maxSkew;
self.maxFundingVelocity = params.maxFundingVelocity;
self.minTradeSizeX18 = params.minTradeSizeX18;
self.skewScale = params.skewScale;
self.orderFees = params.orderFees;
+ self.priceFeedHeartbeatSeconds = params.priceFeedHeartbeatSeconds;
}