Omniscia Euler Finance Audit

PythOracle Code Style Findings

PythOracle Code Style Findings

POE-01C: Potentially Redundant Function Implementation

Description:

In contrast to the RedstoneCoreOracle::updatePrice function that records local data points, the PythOracle::updatePrice function will simply forward a call to a permissionless function of the IPyth implementation.

Impact:

As the PythOracle::updatePrice function does not expose any novel statements and simply forwards a call with no additional logic, its presence is unnecessary and integrators should make sure the oracles are updated whenever necessary.

Example:

src/adapter/pyth/PythOracle.sol
48/// @notice Update the price of the Pyth feed.
49/// @param updateData Price update data. Must be fetched off-chain.
50/// @dev The required fee can be computed by calling `getUpdateFee` on Pyth with the length of the `updateData` array.
51function updatePrice(bytes[] calldata updateData) external payable {
52 IPyth(pyth).updatePriceFeeds{value: msg.value}(updateData);
53}

Recommendation:

We advise the function to be removed altogether, ensuring the caller is responsible for updating the IPyth oracle data points if necessary.

Alleviation:

The relevant function has been properly removed from the PythOracle implementation, and the Euler Finance team has clarified that callers are expected to update the Pyth oracle price via a batch EVK call directly.

POE-02C: Redundant Handling of Positive Exponent

Description:

Per the Pyth Network Solidity SDK validation as well as what a positive exponent would infer, the Pyth Network is expected to report solely non-positive exponent values during its operation. As a result, custom handling of a potentially positive exponent in the ScaleUtils implementation is unnecessary.

Example:

src/adapter/pyth/PythOracle.sol
55/// @notice Fetch the latest Pyth price and transform it to a quote.
56/// @param inAmount The amount of `base` to convert.
57/// @param _base The token that is being priced.
58/// @param _quote The token that is the unit of account.
59/// @return The converted amount.
60function _getQuote(uint256 inAmount, address _base, address _quote) internal view override returns (uint256) {
61 bool inverse = ScaleUtils.getDirectionOrRevert(_base, base, _quote, quote);
62
63 PythStructs.Price memory priceStruct = _fetchPriceStruct();
64 uint256 price = uint256(uint64(priceStruct.price));
65
66 Scale scale = ScaleUtils.calcScale(baseDecimals, quoteDecimals, int8(priceStruct.expo));
67 return ScaleUtils.calcOutAmount(inAmount, price, scale, inverse);
68}
69
70/// @notice Get the latest Pyth price and perform sanity checks.
71/// @dev Reverts if price is non-positive, confidence is too wide, or exponent is too large.
72function _fetchPriceStruct() internal view returns (PythStructs.Price memory) {
73 PythStructs.Price memory p = IPyth(pyth).getPriceNoOlderThan(feedId, maxStaleness);
74 if (p.price <= 0 || p.conf > uint64(p.price) * MAX_CONF_WIDTH / 10_000 || p.expo > 16 || p.expo < -16) {
75 revert Errors.PriceOracle_InvalidAnswer();
76 }
77 return p;
78}

Recommendation:

We advise the priceStruct.expo to be cast to a uint8 after being negated, optimizing the bytecode size of the contracts whilst reducing their complexity.

Alleviation:

Alongside remediations carried out for POE-04M, the referenced statement was optimized to invoke ScaleUtils::from directly thus addressing this exhibit.