Skip to content

Commit

Permalink
Merge branch 'woof-software/add-two-new-pricefeed' of github.com:woof…
Browse files Browse the repository at this point in the history
…-software/comet into woof-software/add-rsweth-to-mainnet-weth
  • Loading branch information
MishaShWoof committed Aug 5, 2024
2 parents b791d32 + 80f08d1 commit 3927bf6
Show file tree
Hide file tree
Showing 4 changed files with 206 additions and 0 deletions.
6 changes: 6 additions & 0 deletions contracts/IRateProvider.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

interface IRateProvider {
function getRate() external view returns (uint256);
}
97 changes: 97 additions & 0 deletions contracts/pricefeeds/RateBasedScalingPriceFeed.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "../vendor/@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "../IPriceFeed.sol";
import "../IRateProvider.sol";

/**
* @title Scaling price feed for rate based oracles
* @notice A custom price feed that scales up or down the price received from an underlying price feed and returns the result
* @author Compound
*/
contract RateBasedScalingPriceFeed is IPriceFeed {
/** Custom errors **/
error InvalidInt256();
error BadDecimals();

/// @notice Version of the price feed
uint public constant VERSION = 1;

/// @notice Description of the price feed
string public description;

/// @notice Number of decimals for returned prices
uint8 public immutable override decimals;

/// @notice Underlying price feed where prices are fetched from
address public immutable underlyingPriceFeed;

/// @notice Whether or not the price should be upscaled
bool internal immutable shouldUpscale;

/// @notice The amount to upscale or downscale the price by
int256 internal immutable rescaleFactor;

/**
* @notice Construct a new scaling price feed
* @param underlyingPriceFeed_ The address of the underlying price feed to fetch prices from
* @param decimals_ The number of decimals for the returned prices
**/
constructor(address underlyingPriceFeed_, uint8 decimals_, uint8 underlyingDecimals_, string memory description_) {
underlyingPriceFeed = underlyingPriceFeed_;
if (decimals_ > 18) revert BadDecimals();
decimals = decimals_;
description = description_;

uint8 priceFeedDecimals = underlyingDecimals_;
// Note: Solidity does not allow setting immutables in if/else statements
shouldUpscale = priceFeedDecimals < decimals_ ? true : false;
rescaleFactor = (shouldUpscale
? signed256(10 ** (decimals_ - priceFeedDecimals))
: signed256(10 ** (priceFeedDecimals - decimals_))
);
}

Check warning

Code scanning / Semgrep OSS

There're no sanity checks for the constructor argument description_. Warning

There're no sanity checks for the constructor argument description_.

Check warning

Code scanning / Semgrep OSS

There're no sanity checks for the constructor argument underlyingDecimals_. Warning

There're no sanity checks for the constructor argument underlyingDecimals_.

Check warning

Code scanning / Semgrep OSS

There're no sanity checks for the constructor argument underlyingPriceFeed_. Warning

There're no sanity checks for the constructor argument underlyingPriceFeed_.

Check warning

Code scanning / Semgrep OSS

Consider making costructor payable to save gas. Warning

Consider making costructor payable to save gas.

/**
* @notice Price for the latest round
* @return roundId Round id from the underlying price feed
* @return answer Latest price for the asset in terms of ETH
* @return startedAt Timestamp when the round was started; passed on from underlying price feed
* @return updatedAt Timestamp when the round was last updated; passed on from underlying price feed
* @return answeredInRound Round id in which the answer was computed; passed on from underlying price feed
**/
function latestRoundData() override external view returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
) {
uint256 rate = IRateProvider(underlyingPriceFeed).getRate();

Check warning

Code scanning / Semgrep OSS

IRateProvider(underlyingPriceFeed).getRate() call on a Balancer pool is not protected from the read-only reentrancy. Warning

IRateProvider(underlyingPriceFeed).getRate() call on a Balancer pool is not protected from the read-only reentrancy.
return (1, scalePrice(signed256(rate)), block.timestamp, block.timestamp, 1);
}

function signed256(uint256 n) internal pure returns (int256) {
if (n > uint256(type(int256).max)) revert InvalidInt256();
return int256(n);
}

function scalePrice(int256 price) internal view returns (int256) {
int256 scaledPrice;
if (shouldUpscale) {
scaledPrice = price * rescaleFactor;
} else {
scaledPrice = price / rescaleFactor;
}
return scaledPrice;
}

/**
* @notice Contract version
* @return The version of the price feed contract
**/
function version() external pure returns (uint256) {
return VERSION;
}
}
97 changes: 97 additions & 0 deletions contracts/pricefeeds/RsETHScalingPriceFeed.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

import "../vendor/@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
import "../vendor/kelp/ILRTOracle.sol";
import "../IPriceFeed.sol";

/**
* @title Scaling price feed for rsETH
* @notice A custom price feed that scales up or down the price received from an underlying Kelp price feed and returns the result
* @author Compound
*/
contract rsETHScalingPriceFeed is IPriceFeed {

Check warning on line 13 in contracts/pricefeeds/RsETHScalingPriceFeed.sol

View workflow job for this annotation

GitHub Actions / Contract linter

Contract name must be in CamelCase
/** Custom errors **/
error InvalidInt256();
error BadDecimals();

/// @notice Version of the price feed
uint public constant VERSION = 1;

/// @notice Description of the price feed
string public description;

/// @notice Number of decimals for returned prices
uint8 public immutable override decimals;

/// @notice Underlying Kelp price feed where prices are fetched from
address public immutable underlyingPriceFeed;

/// @notice Whether or not the price should be upscaled
bool internal immutable shouldUpscale;

/// @notice The amount to upscale or downscale the price by
int256 internal immutable rescaleFactor;

/**
* @notice Construct a new scaling price feed
* @param underlyingPriceFeed_ The address of the underlying price feed to fetch prices from
* @param decimals_ The number of decimals for the returned prices
**/
constructor(address underlyingPriceFeed_, uint8 decimals_, string memory description_) {
underlyingPriceFeed = underlyingPriceFeed_;
if (decimals_ > 18) revert BadDecimals();
decimals = decimals_;
description = description_;

uint8 underlyingPriceFeedDecimals = 18;
// Note: Solidity does not allow setting immutables in if/else statements
shouldUpscale = underlyingPriceFeedDecimals < decimals_ ? true : false;
rescaleFactor = (shouldUpscale
? signed256(10 ** (decimals_ - underlyingPriceFeedDecimals))
: signed256(10 ** (underlyingPriceFeedDecimals - decimals_))
);
}

Check warning

Code scanning / Semgrep OSS

There're no sanity checks for the constructor argument description_. Warning

There're no sanity checks for the constructor argument description_.

Check warning

Code scanning / Semgrep OSS

There're no sanity checks for the constructor argument underlyingPriceFeed_. Warning

There're no sanity checks for the constructor argument underlyingPriceFeed_.

Check warning

Code scanning / Semgrep OSS

Consider making costructor payable to save gas. Warning

Consider making costructor payable to save gas.

/**
* @notice Price for the latest round
* @return roundId Round id from the underlying price feed
* @return answer Latest price for the asset in terms of ETH
* @return startedAt Timestamp when the round was started; passed on from underlying price feed
* @return updatedAt Timestamp when the round was last updated; passed on from underlying price feed
* @return answeredInRound Round id in which the answer was computed; passed on from underlying price feed
**/
function latestRoundData() override external view returns (
uint80 roundId,
int256 answer,
uint256 startedAt,
uint256 updatedAt,
uint80 answeredInRound
) {
int256 price = signed256(ILRTOracle(underlyingPriceFeed).rsETHPrice());
return (1, scalePrice(price), block.timestamp, block.timestamp, 1);
}

function signed256(uint256 n) internal pure returns (int256) {
if (n > uint256(type(int256).max)) revert InvalidInt256();
return int256(n);
}

function scalePrice(int256 price) internal view returns (int256) {
int256 scaledPrice;
if (shouldUpscale) {
scaledPrice = price * rescaleFactor;
} else {
scaledPrice = price / rescaleFactor;
}
return scaledPrice;
}

/**
* @notice Contract version
* @return The version of the price feed contract
**/
function version() external pure returns (uint256) {
return VERSION;
}
}
6 changes: 6 additions & 0 deletions contracts/vendor/kelp/ILRTOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.15;

interface ILRTOracle {
function rsETHPrice() external view returns (uint256);
}

0 comments on commit 3927bf6

Please sign in to comment.