-
Notifications
You must be signed in to change notification settings - Fork 28
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #4 from morpho-labs/feat/chainlink-threeway
Chainlink threeway oracles
- Loading branch information
Showing
4 changed files
with
99 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity 0.8.19; | ||
|
||
import {IOracle} from "morpho-blue/interfaces/IOracle.sol"; | ||
|
||
import {AggregatorV3Interface, DataFeedLib} from "./libraries/DataFeedLib.sol"; | ||
|
||
contract OracleThreeWay is IOracle { | ||
using DataFeedLib for AggregatorV3Interface; | ||
|
||
/* CONSTANT */ | ||
|
||
/// @notice First base feed. | ||
AggregatorV3Interface public immutable FIRST_BASE_FEED; | ||
/// @notice Second base feed. | ||
AggregatorV3Interface public immutable SECOND_BASE_FEED; | ||
/// @notice Quote feed. | ||
AggregatorV3Interface public immutable QUOTE_FEED; | ||
/// @notice Price scale factor. Automatically computed at contract creation. | ||
uint256 public immutable SCALE_FACTOR; | ||
|
||
/* CONSTRUCTOR */ | ||
|
||
/// @param firstBaseFeed First base feed. | ||
/// @param secondBaseFeed Second base feed. | ||
/// @param quoteFeed Quote feed. Pass address zero if the price = 1. | ||
/// @param baseTokenDecimals Base token decimals. | ||
/// @param quoteTokenDecimals Quote token decimals. Pass 0 if the price = 1. | ||
constructor( | ||
AggregatorV3Interface firstBaseFeed, | ||
AggregatorV3Interface secondBaseFeed, | ||
AggregatorV3Interface quoteFeed, | ||
uint256 baseTokenDecimals, | ||
uint256 quoteTokenDecimals | ||
) { | ||
FIRST_BASE_FEED = firstBaseFeed; | ||
SECOND_BASE_FEED = secondBaseFeed; | ||
QUOTE_FEED = quoteFeed; | ||
// SCALE_FACTOR = 10 ** (36 + (quoteFeedDecimals - quoteTokenDecimals) - (firstBaseFeedDecimals + | ||
// secondBaseFeedDecimals - baseTokenDecimals)) | ||
SCALE_FACTOR = 10 | ||
** ( | ||
36 + baseTokenDecimals + quoteFeed.getDecimals() - firstBaseFeed.getDecimals() | ||
- secondBaseFeed.getDecimals() - quoteTokenDecimals | ||
); | ||
} | ||
|
||
/* PRICE */ | ||
|
||
/// @inheritdoc IOracle | ||
function price() external view returns (uint256) { | ||
return (FIRST_BASE_FEED.getPrice() * SECOND_BASE_FEED.getPrice() * SCALE_FACTOR) / QUOTE_FEED.getPrice(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
// SPDX-License-Identifier: UNLICENSED | ||
pragma solidity ^0.8.0; | ||
|
||
import "forge-std/Test.sol"; | ||
import "src/chainlink/OracleThreeWay.sol"; | ||
import "src/chainlink/libraries/ErrorsLib.sol"; | ||
|
||
// 8 decimals of precision | ||
AggregatorV3Interface constant btcUsdFeed = AggregatorV3Interface(0xF4030086522a5bEEa4988F8cA5B36dbC97BeE88c); | ||
// 8 decimals of precision | ||
AggregatorV3Interface constant usdcUsdFeed = AggregatorV3Interface(0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6); | ||
// 18 decimals of precision | ||
AggregatorV3Interface constant btcEthFeed = AggregatorV3Interface(0xdeb288F737066589598e9214E782fa5A8eD689e8); | ||
// 8 decimals of precision | ||
AggregatorV3Interface constant wBtcBtcFeed = AggregatorV3Interface(0xfdFD9C85aD200c506Cf9e21F1FD8dd01932FBB23); | ||
|
||
contract OracleTest is Test { | ||
function setUp() public { | ||
vm.selectFork(vm.createFork(vm.envString("ETH_RPC_URL"))); | ||
} | ||
|
||
function testOracleWbtcUsdc() public { | ||
OracleThreeWay oracle = new OracleThreeWay(wBtcBtcFeed, btcUsdFeed, usdcUsdFeed, 8, 6); | ||
(, int256 firstBaseAnswer,,,) = wBtcBtcFeed.latestRoundData(); | ||
(, int256 secondBaseAnswer,,,) = btcUsdFeed.latestRoundData(); | ||
(, int256 quoteAnswer,,,) = usdcUsdFeed.latestRoundData(); | ||
assertEq( | ||
oracle.price(), | ||
(uint256(firstBaseAnswer) * uint256(secondBaseAnswer) * 10 ** (36 + 8 + 8 - 6 - 8 - 8)) | ||
/ uint256(quoteAnswer) | ||
); | ||
} | ||
|
||
function testOracleWbtcEth() public { | ||
OracleThreeWay oracle = new OracleThreeWay(wBtcBtcFeed, btcEthFeed, AggregatorV3Interface(address(0)), 8, 0); | ||
(, int256 firstBaseAnswer,,,) = wBtcBtcFeed.latestRoundData(); | ||
(, int256 secondBaseAnswer,,,) = btcEthFeed.latestRoundData(); | ||
assertEq(oracle.price(), (uint256(firstBaseAnswer) * uint256(secondBaseAnswer) * 10 ** (36 + 8 - 8 - 18))); | ||
} | ||
} |