-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,90 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity 0.8.15; | ||
|
||
import "../vendor/@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; | ||
import "../IPriceFeed.sol"; | ||
|
||
interface IRateProvider { | ||
function getRate() external view returns (uint256); | ||
} | ||
|
||
/** | ||
* @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(); | ||
|
||
/// @notice Version of the price feed | ||
uint public constant override version = 1; | ||
Check notice Code scanning / Semgrep OSS Semgrep Finding: compound.solidity.constant-not-in-uppercase Note
A constant name is not in UPPER_CASE like other constant variables.
|
||
|
||
/// @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_; | ||
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 Semgrep Finding: compound.solidity.missing-constructor-sanity-checks 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 failure Code scanning / Semgrep OSS Semgrep Finding: rules.solidity.security.balancer-readonly-reentrancy-getrate Error
IRateProvider(underlyingPriceFeed).getRate() call on a Balancer pool is not protected from the read-only reentrancy.
|
||
return (roundId, scalePrice(int256(rate)), startedAt, updatedAt, answeredInRound); | ||
} | ||
|
||
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; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
// SPDX-License-Identifier: BUSL-1.1 | ||
pragma solidity 0.8.15; | ||
|
||
import "../vendor/@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol"; | ||
import "../vendor/kelp/IrsETHOracle.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 { | ||
/** Custom errors **/ | ||
error InvalidInt256(); | ||
|
||
/// @notice Version of the price feed | ||
uint public constant override version = 1; | ||
Check notice Code scanning / Semgrep OSS Semgrep Finding: compound.solidity.constant-not-in-uppercase Note
A constant name is not in UPPER_CASE like other constant variables.
|
||
|
||
/// @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_; | ||
decimals = decimals_; | ||
description = description_; | ||
|
||
uint8 kelpPriceFeedDecimals = 18; | ||
// Note: Solidity does not allow setting immutables in if/else statements | ||
shouldUpscale = kelpPriceFeedDecimals < decimals_ ? true : false; | ||
rescaleFactor = (shouldUpscale | ||
? signed256(10 ** (decimals_ - kelpPriceFeedDecimals)) | ||
: signed256(10 ** (kelpPriceFeedDecimals - decimals_)) | ||
); | ||
} | ||
Check warning Code scanning / Semgrep OSS Semgrep Finding: compound.solidity.missing-constructor-sanity-checks Warning
There're no sanity checks for the constructor argument decimals_.
Check warning Code scanning / Semgrep OSS Semgrep Finding: compound.solidity.missing-constructor-sanity-checks Warning
There're no sanity checks for the constructor argument description_.
Check warning Code scanning / Semgrep OSS Semgrep Finding: compound.solidity.missing-constructor-sanity-checks Warning
There're no sanity checks for the constructor argument underlyingPriceFeed_.
Check notice Code scanning / Semgrep OSS Semgrep Finding: rules.solidity.performance.non-payable-constructor Note
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 = int256(IrsETHOracle(underlyingPriceFeed).rsETHPrice()); | ||
return (roundId, scalePrice(price), startedAt, updatedAt, answeredInRound); | ||
} | ||
|
||
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; | ||
} | ||
} |
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 IrsETHOracle { | ||
function rsETHPrice() external view returns (uint256); | ||
} |