DeFiFoundry
60,000 USDC
View results
Submission Details
Severity: low
Valid

`verifyOffchainPrice` does not pay native fee for offchain data

Summary

verifyOffchainPrice does not pay native fee for offchain data. The protocol is supposed to pay the fee to chainlink for their services but in the code it is not enforced.

Root Cause

https://github.com/Cyfrin/2024-07-zaros/blob/d687fe96bb7ace8652778797052a38763fbcbb1b/src/perpetuals/branches/SettlementBranch.sol#L107-L166
https://github.com/Cyfrin/2024-07-zaros/blob/d687fe96bb7ace8652778797052a38763fbcbb1b/src/perpetuals/branches/SettlementBranch.sol#L138-L139

In SettlementBranch when the keeper wants to fillMarketOrder or fillOffchainsOrders he should pay the fee in native token for verifing the report. However fillMarketOrder and fillOffchainsOrders are non-payable. Native tokens can not be sent with the function call.

Vulnerability details

(ctx.bidX18, ctx.askX18) =
settlementConfiguration.verifyOffchainPrice(priceData, globalConfiguration.maxVerificationDelay);

These functions call verifyOffchainPrice.

function verifyOffchainPrice(
Data storage self,
bytes memory priceData,
uint256 maxVerificationDelay
)
internal
returns (UD60x18 bidX18, UD60x18 askX18)
{
if (self.strategy == Strategy.DATA_STREAMS_DEFAULT) {
DataStreamsStrategy memory dataStreamsStrategy = abi.decode(self.data, (DataStreamsStrategy));
bytes memory verifiedPriceData = verifyDataStreamsReport(dataStreamsStrategy, priceData);
requireDataStreamsReportIsValid(dataStreamsStrategy.streamId, verifiedPriceData, maxVerificationDelay);
PremiumReport memory premiumReport = abi.decode(verifiedPriceData, (PremiumReport));
(bidX18, askX18) =
(ud60x18(int256(premiumReport.bid).toUint256()), ud60x18(int256(premiumReport.ask).toUint256()));
} else {
revert Errors.InvalidSettlementStrategy();
}
}

verifyOffchainPrice calls verifyDataStreamsReport.

function verifyDataStreamsReport(
DataStreamsStrategy memory dataStreamsStrategy,
bytes memory signedReport
)
internal
returns (bytes memory verifiedReportData)
{
IVerifierProxy chainlinkVerifier = dataStreamsStrategy.chainlinkVerifier;
bytes memory reportData = ChainlinkUtil.getReportData(signedReport);
(FeeAsset memory fee) = ChainlinkUtil.getEthVericationFee(chainlinkVerifier, reportData);
verifiedReportData = ChainlinkUtil.verifyReport(chainlinkVerifier, fee, signedReport);
}

verifyDataStreamsReport calls getReportData, getEthVericationFee and verifyReport. verifyReport has fee as one of the input parameters which is calculated in getEthVericationFee.

function verifyReport(
IVerifierProxy chainlinkVerifier,
FeeAsset memory fee,
bytes memory signedReport
)
internal
returns (bytes memory verifiedReportData)
{
verifiedReportData = chainlinkVerifier.verify{ value: fee.amount }(signedReport, abi.encode(fee.assetAddress));
}

Finally verifyReport calls verify which requires payment. It is calculated but never sent.

Impact

Protocol won't be able to verify prices. All functionality based on that will be unavailable for users. The protocol will suffer from DoS.

Recommended Mitigation Steps

Pay the required fee in native token or in link token as suggested in chainlink docs.

https://docs.chain.link/chainlink-automation/guides/streams-lookup

Updates

Lead Judging Commences

inallhonesty Lead Judge about 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

No means for the PerpEngine to receive native to pay the Chainlink Verifier in case Chainlinks charges fees to the protocol

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.