Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor oracles #70

Merged
merged 23 commits into from
Aug 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
9c3d9df
refactor: draft
MerlinEgalite Aug 20, 2023
028c76a
refactor: fix inheritance graph
MerlinEgalite Aug 20, 2023
e50caf4
chore: disable via ir to allow compilation
MerlinEgalite Aug 20, 2023
1bf5581
fix: correct visibility
MerlinEgalite Aug 21, 2023
3057612
refactor: explicit overriding
MerlinEgalite Aug 21, 2023
909bc7e
docs: add oracle doc
MerlinEgalite Aug 21, 2023
7e24a8d
feat: use lib
MerlinEgalite Aug 21, 2023
5218701
refactor(oracle): remove redundant overrides
Rubilmax Aug 21, 2023
57ead6e
refactor(oracle): remove redundant getters
Rubilmax Aug 21, 2023
63ba502
refactor(format): format BundleAction
Rubilmax Aug 21, 2023
baa19fa
Merge branch 'refactor/oracles' of github.com:morpho-labs/morpho-blue…
Rubilmax Aug 21, 2023
d14ed62
test(oracle): fix tests
Rubilmax Aug 21, 2023
2604607
fix: static
MerlinEgalite Aug 21, 2023
555d822
Merge pull request #74 from morpho-labs/refactor/oracles-base
MerlinEgalite Aug 21, 2023
b990b59
test: remove console.log oops
MerlinEgalite Aug 21, 2023
d51bbca
docs: apply suggestions
MerlinEgalite Aug 21, 2023
6754f81
chore: roll back foundry config
MerlinEgalite Aug 21, 2023
5929304
refactor: capital letters + immutables
MerlinEgalite Aug 21, 2023
22d9a75
refactor: less verbose naming
MerlinEgalite Aug 21, 2023
ab57765
refactor: use immutables in BaseOracle directly
MerlinEgalite Aug 21, 2023
f8019b3
Merge pull request #77 from morpho-labs/refactor/oracles-3
MerlinEgalite Aug 21, 2023
d5baa2f
Merge pull request #76 from morpho-labs/refactor/oracles-2
MerlinEgalite Aug 21, 2023
1634554
docs: apply suggestion
MerlinEgalite Aug 21, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@
User-end bundlers are provided in each chain-specific folder, instanciating all the intermediary domain-specific bundlers and associated parameters (such as chain-specific protocol addresses) as well as a [`SelfMulticall`](./contracts/bundlers/SelfMulticall.sol) that enables bundling multiple function calls into a single `multicall(uint256 deadline, bytes[] calldata data)` call to the end bundler contract.
- [`routers/`](./contracts/routers/):
- [`flash/`](./contracts/routers/flash/): exposes a flash loan router contract that bundles flash loans from multiple flash lenders into a single call, expecting the initiator to provide enough funds to repay every flash loan and its associated fees. The flash router contract automatically pulls tokens from the initiator at the end of the flash loan.
- [`oracles/`](./contracts/oracles/): you'll find all oracles that can be used in Morpho Blue. A Morpho Blue oracle should inherit from [`BaseOracle`](./contracts/oracles/BaseOracle.sol), one collateral adapter and one borrowable adapter.
- [`adapters/`](./contracts/oracles/adapters/): adapters are contracts that adapt a specific oracle type (e.g. Chainlink) to one side of the market (e.g. the collateral side). Adapters should be inherited by pair (one collateral adapter and one borrowable adapter) along [`BaseOracle`](./contracts/oracles/BaseOracle.sol) to build a fully complete oracle.
- [`libraries/`](./contracts/oracles/libraries/): gathers all the logic to interact with a specific type of oracle.
31 changes: 31 additions & 0 deletions contracts/oracles/BaseOracle.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IOracle} from "./interfaces/IOracle.sol";

import {FullMath} from "@uniswap/v3-core/libraries/FullMath.sol";

abstract contract BaseOracle is IOracle {
using FullMath for uint256;

/// @dev The scale must be 1e36 * 10^(decimals of borrowable token - decimals of collateral token).
uint256 public immutable PRICE_SCALE;

// @dev The collateral price's unit.
uint256 public immutable COLLATERAL_SCALE;

// @dev The borrowable price's unit.
uint256 public immutable BORROWABLE_SCALE;

constructor(uint256 priceScale) {
PRICE_SCALE = priceScale;
}

function price() external view returns (uint256) {
// Using FullMath to avoid overflowing because of PRICE_SCALE.
return PRICE_SCALE.mulDiv(collateralPrice() * BORROWABLE_SCALE, borrowablePrice() * COLLATERAL_SCALE);
}

function collateralPrice() public view virtual returns (uint256);
function borrowablePrice() public view virtual returns (uint256);
}
24 changes: 4 additions & 20 deletions contracts/oracles/ChainlinkOracle.sol
Original file line number Diff line number Diff line change
@@ -1,26 +1,10 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IOracle} from "./interfaces/IOracle.sol";
import {IChainlinkAggregatorV3} from "./adapters/interfaces/IChainlinkAggregatorV3.sol";

import {OracleFeed} from "./libraries/OracleFeed.sol";
import {ChainlinkAggregatorV3Lib} from "./libraries/ChainlinkAggregatorV3Lib.sol";

import {BaseOracle} from "./BaseOracle.sol";
import {StaticBorrowableAdapter} from "./adapters/StaticBorrowableAdapter.sol";
import {ChainlinkCollateralAdapter} from "./adapters/ChainlinkCollateralAdapter.sol";

contract ChainlinkOracle is ChainlinkCollateralAdapter, IOracle {
using ChainlinkAggregatorV3Lib for IChainlinkAggregatorV3;

constructor(address feed) ChainlinkCollateralAdapter(feed) {}

function FEED_COLLATERAL() external view returns (string memory, address) {
return (OracleFeed.CHAINLINK_V3, address(CHAINLINK_COLLATERAL_FEED));
}

function FEED_BORROWABLE() external view returns (string memory, address) {}

function price() external view returns (uint256) {
return CHAINLINK_COLLATERAL_FEED.price();
}
contract ChainlinkOracle is BaseOracle, ChainlinkCollateralAdapter, StaticBorrowableAdapter {
constructor(uint256 priceScale, address feed) BaseOracle(priceScale) ChainlinkCollateralAdapter(feed) {}
}
38 changes: 5 additions & 33 deletions contracts/oracles/ChainlinkPairOracle.sol
Original file line number Diff line number Diff line change
@@ -1,42 +1,14 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IOracle} from "./interfaces/IOracle.sol";
import {IChainlinkAggregatorV3} from "./adapters/interfaces/IChainlinkAggregatorV3.sol";

import {OracleFeed} from "./libraries/OracleFeed.sol";
import {FullMath} from "@uniswap/v3-core/libraries/FullMath.sol";
import {ChainlinkAggregatorV3Lib} from "./libraries/ChainlinkAggregatorV3Lib.sol";

import {BaseOracle} from "./BaseOracle.sol";
import {ChainlinkCollateralAdapter} from "./adapters/ChainlinkCollateralAdapter.sol";
import {ChainlinkBorrowableAdapter} from "./adapters/ChainlinkBorrowableAdapter.sol";

contract ChainlinkPairOracle is ChainlinkCollateralAdapter, ChainlinkBorrowableAdapter, IOracle {
using ChainlinkAggregatorV3Lib for IChainlinkAggregatorV3;

/// @dev The scale must be 1e36 * 10^(decimals of borrowable token - decimals of collateral token).
uint256 public immutable PRICE_SCALE;

constructor(address collateralFeed, address borrowableFeed, uint256 scale)
contract ChainlinkPairOracle is BaseOracle, ChainlinkCollateralAdapter, ChainlinkBorrowableAdapter {
constructor(uint256 priceScale, address collateralFeed, address borrowableFeed)
BaseOracle(priceScale)
ChainlinkCollateralAdapter(collateralFeed)
ChainlinkBorrowableAdapter(borrowableFeed)
{
PRICE_SCALE = scale;
}

function FEED_COLLATERAL() external view returns (string memory, address) {
return (OracleFeed.CHAINLINK_V3, address(CHAINLINK_COLLATERAL_FEED));
}

function FEED_BORROWABLE() external view returns (string memory, address) {
return (OracleFeed.CHAINLINK_V3, address(CHAINLINK_BORROWABLE_FEED));
}

function price() external view returns (uint256) {
return FullMath.mulDiv(
CHAINLINK_COLLATERAL_FEED.price() * CHAINLINK_BORROWABLE_PRICE_SCALE,
PRICE_SCALE, // Using FullMath to avoid overflowing because of PRICE_SCALE.
CHAINLINK_BORROWABLE_FEED.price() * CHAINLINK_COLLATERAL_PRICE_SCALE
);
}
{}
}
43 changes: 5 additions & 38 deletions contracts/oracles/ChainlinkUniswapV3Oracle.sol
Original file line number Diff line number Diff line change
@@ -1,47 +1,14 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IOracle} from "./interfaces/IOracle.sol";
import {IUniswapV3Pool} from "@uniswap/v3-core/interfaces/IUniswapV3Pool.sol";
import {IChainlinkAggregatorV3} from "./adapters/interfaces/IChainlinkAggregatorV3.sol";

import {OracleFeed} from "./libraries/OracleFeed.sol";
import {WAD, MathLib} from "@morpho-blue/libraries/MathLib.sol";
import {FullMath} from "@uniswap/v3-core/libraries/FullMath.sol";
import {UniswapV3PoolLib} from "./libraries/UniswapV3PoolLib.sol";
import {ChainlinkAggregatorV3Lib} from "./libraries/ChainlinkAggregatorV3Lib.sol";

import {BaseOracle} from "./BaseOracle.sol";
import {ChainlinkCollateralAdapter} from "./adapters/ChainlinkCollateralAdapter.sol";
import {UniswapV3BorrowableAdapter} from "./adapters/UniswapV3BorrowableAdapter.sol";

contract ChainlinkUniswapV3Oracle is ChainlinkCollateralAdapter, UniswapV3BorrowableAdapter, IOracle {
using MathLib for uint256;
using UniswapV3PoolLib for IUniswapV3Pool;
using ChainlinkAggregatorV3Lib for IChainlinkAggregatorV3;

/// @dev The scale must be 1e36 * 10^(decimals of borrowable token - decimals of collateral token).
uint256 public immutable PRICE_SCALE;

constructor(address feed, address pool, uint32 borrowablePriceDelay, uint256 scale)
contract ChainlinkUniswapV3Oracle is BaseOracle, ChainlinkCollateralAdapter, UniswapV3BorrowableAdapter {
constructor(uint256 priceScale, address feed, address pool, uint32 borrowablePriceDelay)
BaseOracle(priceScale)
ChainlinkCollateralAdapter(feed)
UniswapV3BorrowableAdapter(pool, borrowablePriceDelay)
{
PRICE_SCALE = scale;
}

function FEED_COLLATERAL() external view returns (string memory, address) {
return (OracleFeed.CHAINLINK_V3, address(CHAINLINK_COLLATERAL_FEED));
}

function FEED_BORROWABLE() external view returns (string memory, address) {
return (OracleFeed.UNISWAP_V3, address(UNI_V3_BORROWABLE_POOL));
}

function price() external view returns (uint256) {
return FullMath.mulDiv(
CHAINLINK_COLLATERAL_FEED.price() * WAD,
PRICE_SCALE, // Using FullMath to avoid overflowing because of PRICE_SCALE.
UNI_V3_BORROWABLE_POOL.price(UNI_V3_BORROWABLE_DELAY) * CHAINLINK_COLLATERAL_PRICE_SCALE
);
}
{}
}
43 changes: 5 additions & 38 deletions contracts/oracles/UniswapV3ChainlinkOracle.sol
Original file line number Diff line number Diff line change
@@ -1,47 +1,14 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IOracle} from "./interfaces/IOracle.sol";
import {IUniswapV3Pool} from "@uniswap/v3-core/interfaces/IUniswapV3Pool.sol";
import {IChainlinkAggregatorV3} from "./adapters/interfaces/IChainlinkAggregatorV3.sol";

import {OracleFeed} from "./libraries/OracleFeed.sol";
import {WAD, MathLib} from "@morpho-blue/libraries/MathLib.sol";
import {FullMath} from "@uniswap/v3-core/libraries/FullMath.sol";
import {UniswapV3PoolLib} from "./libraries/UniswapV3PoolLib.sol";
import {ChainlinkAggregatorV3Lib} from "./libraries/ChainlinkAggregatorV3Lib.sol";

import {BaseOracle} from "./BaseOracle.sol";
import {UniswapV3CollateralAdapter} from "./adapters/UniswapV3CollateralAdapter.sol";
import {ChainlinkBorrowableAdapter} from "./adapters/ChainlinkBorrowableAdapter.sol";

contract UniswapV3ChainlinkOracle is UniswapV3CollateralAdapter, ChainlinkBorrowableAdapter, IOracle {
using MathLib for uint256;
using UniswapV3PoolLib for IUniswapV3Pool;
using ChainlinkAggregatorV3Lib for IChainlinkAggregatorV3;

/// @dev The scale must be 1e36 * 10^(decimals of borrowable token - decimals of collateral token).
uint256 public immutable PRICE_SCALE;

constructor(address pool, address feed, uint32 collateralPriceDelay, uint256 scale)
contract UniswapV3ChainlinkOracle is BaseOracle, UniswapV3CollateralAdapter, ChainlinkBorrowableAdapter {
constructor(uint256 priceScale, address pool, address feed, uint32 collateralPriceDelay)
BaseOracle(priceScale)
UniswapV3CollateralAdapter(pool, collateralPriceDelay)
ChainlinkBorrowableAdapter(feed)
{
PRICE_SCALE = scale;
}

function FEED_COLLATERAL() external view returns (string memory, address) {
return (OracleFeed.UNISWAP_V3, address(UNI_V3_COLLATERAL_POOL));
}

function FEED_BORROWABLE() external view returns (string memory, address) {
return (OracleFeed.CHAINLINK_V3, address(CHAINLINK_BORROWABLE_FEED));
}

function price() external view returns (uint256) {
return FullMath.mulDiv(
UNI_V3_COLLATERAL_POOL.price(UNI_V3_COLLATERAL_DELAY) * CHAINLINK_BORROWABLE_PRICE_SCALE,
PRICE_SCALE, // Using FullMath to avoid overflowing because of PRICE_SCALE.
CHAINLINK_BORROWABLE_FEED.price() * WAD
);
}
{}
}
27 changes: 7 additions & 20 deletions contracts/oracles/UniswapV3Oracle.sol
Original file line number Diff line number Diff line change
@@ -1,26 +1,13 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IOracle} from "./interfaces/IOracle.sol";
import {IUniswapV3Pool} from "@uniswap/v3-core/interfaces/IUniswapV3Pool.sol";

import {OracleFeed} from "./libraries/OracleFeed.sol";
import {UniswapV3PoolLib} from "./libraries/UniswapV3PoolLib.sol";

import {BaseOracle} from "./BaseOracle.sol";
import {StaticBorrowableAdapter} from "./adapters/StaticBorrowableAdapter.sol";
import {UniswapV3CollateralAdapter} from "./adapters/UniswapV3CollateralAdapter.sol";

contract UniswapV3Oracle is UniswapV3CollateralAdapter, IOracle {
using UniswapV3PoolLib for IUniswapV3Pool;

constructor(address pool, uint32 delay) UniswapV3CollateralAdapter(pool, delay) {}

function FEED_COLLATERAL() external view returns (string memory, address) {
return (OracleFeed.UNISWAP_V3, address(UNI_V3_COLLATERAL_POOL));
}

function FEED_BORROWABLE() external view returns (string memory, address) {}

function price() external view returns (uint256) {
return UNI_V3_COLLATERAL_POOL.price(UNI_V3_COLLATERAL_DELAY);
}
contract UniswapV3Oracle is BaseOracle, UniswapV3CollateralAdapter, StaticBorrowableAdapter {
constructor(uint256 priceScale, address pool, uint32 delay)
BaseOracle(priceScale)
UniswapV3CollateralAdapter(pool, delay)
{}
}
42 changes: 6 additions & 36 deletions contracts/oracles/UniswapV3PairOracle.sol
Original file line number Diff line number Diff line change
@@ -1,50 +1,20 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {IOracle} from "./interfaces/IOracle.sol";
import {IUniswapV3Pool} from "@uniswap/v3-core/interfaces/IUniswapV3Pool.sol";

import {OracleFeed} from "./libraries/OracleFeed.sol";
import {MathLib} from "@morpho-blue/libraries/MathLib.sol";
import {FullMath} from "@uniswap/v3-core/libraries/FullMath.sol";
import {UniswapV3PoolLib} from "./libraries/UniswapV3PoolLib.sol";

import {BaseOracle} from "./BaseOracle.sol";
import {UniswapV3CollateralAdapter} from "./adapters/UniswapV3CollateralAdapter.sol";
import {UniswapV3BorrowableAdapter} from "./adapters/UniswapV3BorrowableAdapter.sol";

contract UniswapV3Oracle is UniswapV3CollateralAdapter, UniswapV3BorrowableAdapter, IOracle {
using MathLib for uint256;
using UniswapV3PoolLib for IUniswapV3Pool;

/// @dev The scale must be 1e36 * 10^(decimals of borrowable token - decimals of collateral token).
uint256 public immutable PRICE_SCALE;

contract UniswapV3Oracle is BaseOracle, UniswapV3CollateralAdapter, UniswapV3BorrowableAdapter {
constructor(
uint256 priceScale,
address collateralPool,
address borrowablePool,
uint32 collateralPriceDelay,
uint32 borrowablePriceDelay,
uint256 scale
uint32 borrowablePriceDelay
)
BaseOracle(priceScale)
UniswapV3CollateralAdapter(collateralPool, collateralPriceDelay)
UniswapV3BorrowableAdapter(borrowablePool, borrowablePriceDelay)
{
PRICE_SCALE = scale;
}

function FEED_COLLATERAL() external view returns (string memory, address) {
return (OracleFeed.UNISWAP_V3, address(UNI_V3_COLLATERAL_POOL));
}

function FEED_BORROWABLE() external view returns (string memory, address) {
return (OracleFeed.UNISWAP_V3, address(UNI_V3_BORROWABLE_POOL));
}

function price() external view returns (uint256) {
return FullMath.mulDiv(
UNI_V3_COLLATERAL_POOL.price(UNI_V3_COLLATERAL_DELAY),
PRICE_SCALE,
UNI_V3_BORROWABLE_POOL.price(UNI_V3_BORROWABLE_DELAY)
);
}
{}
}
24 changes: 19 additions & 5 deletions contracts/oracles/adapters/ChainlinkBorrowableAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,26 @@ pragma solidity ^0.8.0;

import {IChainlinkAggregatorV3} from "./interfaces/IChainlinkAggregatorV3.sol";

abstract contract ChainlinkBorrowableAdapter {
IChainlinkAggregatorV3 public immutable CHAINLINK_BORROWABLE_FEED;
uint256 public immutable CHAINLINK_BORROWABLE_PRICE_SCALE;
import {OracleFeed} from "../libraries/OracleFeed.sol";
import {ChainlinkAggregatorV3Lib} from "../libraries/ChainlinkAggregatorV3Lib.sol";

import {BaseOracle} from "../BaseOracle.sol";

abstract contract ChainlinkBorrowableAdapter is BaseOracle {
using ChainlinkAggregatorV3Lib for IChainlinkAggregatorV3;

IChainlinkAggregatorV3 private immutable _CHAINLINK_BORROWABLE_FEED;

constructor(address feed) {
CHAINLINK_BORROWABLE_FEED = IChainlinkAggregatorV3(feed);
CHAINLINK_BORROWABLE_PRICE_SCALE = 10 ** CHAINLINK_BORROWABLE_FEED.decimals();
_CHAINLINK_BORROWABLE_FEED = IChainlinkAggregatorV3(feed);
BORROWABLE_SCALE = 10 ** _CHAINLINK_BORROWABLE_FEED.decimals();
}

function BORROWABLE_FEED() external view returns (string memory, address) {
return (OracleFeed.CHAINLINK_V3, address(_CHAINLINK_BORROWABLE_FEED));
}

function borrowablePrice() public view virtual override returns (uint256) {
return _CHAINLINK_BORROWABLE_FEED.price();
}
}
24 changes: 19 additions & 5 deletions contracts/oracles/adapters/ChainlinkCollateralAdapter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,26 @@ pragma solidity ^0.8.0;

import {IChainlinkAggregatorV3} from "./interfaces/IChainlinkAggregatorV3.sol";

abstract contract ChainlinkCollateralAdapter {
IChainlinkAggregatorV3 public immutable CHAINLINK_COLLATERAL_FEED;
uint256 public immutable CHAINLINK_COLLATERAL_PRICE_SCALE;
import {OracleFeed} from "../libraries/OracleFeed.sol";
import {ChainlinkAggregatorV3Lib} from "../libraries/ChainlinkAggregatorV3Lib.sol";

import {BaseOracle} from "../BaseOracle.sol";

abstract contract ChainlinkCollateralAdapter is BaseOracle {
using ChainlinkAggregatorV3Lib for IChainlinkAggregatorV3;

IChainlinkAggregatorV3 private immutable _CHAINLINK_COLLATERAL_FEED;

constructor(address feed) {
CHAINLINK_COLLATERAL_FEED = IChainlinkAggregatorV3(feed);
CHAINLINK_COLLATERAL_PRICE_SCALE = 10 ** CHAINLINK_COLLATERAL_FEED.decimals();
_CHAINLINK_COLLATERAL_FEED = IChainlinkAggregatorV3(feed);
COLLATERAL_SCALE = 10 ** _CHAINLINK_COLLATERAL_FEED.decimals();
}

function COLLATERAL_FEED() external view returns (string memory, address) {
return (OracleFeed.CHAINLINK_V3, address(_CHAINLINK_COLLATERAL_FEED));
}

function collateralPrice() public view virtual override returns (uint256) {
return _CHAINLINK_COLLATERAL_FEED.price();
}
}
20 changes: 20 additions & 0 deletions contracts/oracles/adapters/StaticBorrowableAdapter.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.0;

import {OracleFeed} from "../libraries/OracleFeed.sol";

import {BaseOracle} from "../BaseOracle.sol";

abstract contract StaticBorrowableAdapter is BaseOracle {
constructor() {
BORROWABLE_SCALE = 1;
}

function BORROWABLE_FEED() external pure returns (string memory, address) {
return (OracleFeed.STATIC, address(0));
}

function borrowablePrice() public view virtual override returns (uint256) {
return 1;
}
}
Loading