diff --git a/README.md b/README.md index 9067efc2..b242bf4c 100644 --- a/README.md +++ b/README.md @@ -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. diff --git a/contracts/oracles/BaseOracle.sol b/contracts/oracles/BaseOracle.sol new file mode 100644 index 00000000..290f8100 --- /dev/null +++ b/contracts/oracles/BaseOracle.sol @@ -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); +} diff --git a/contracts/oracles/ChainlinkOracle.sol b/contracts/oracles/ChainlinkOracle.sol index 8edd546a..29eab8c7 100644 --- a/contracts/oracles/ChainlinkOracle.sol +++ b/contracts/oracles/ChainlinkOracle.sol @@ -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) {} } diff --git a/contracts/oracles/ChainlinkPairOracle.sol b/contracts/oracles/ChainlinkPairOracle.sol index b6ae40fb..9b2d7064 100644 --- a/contracts/oracles/ChainlinkPairOracle.sol +++ b/contracts/oracles/ChainlinkPairOracle.sol @@ -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 - ); - } + {} } diff --git a/contracts/oracles/ChainlinkUniswapV3Oracle.sol b/contracts/oracles/ChainlinkUniswapV3Oracle.sol index f8391e7a..5b8c1fe4 100644 --- a/contracts/oracles/ChainlinkUniswapV3Oracle.sol +++ b/contracts/oracles/ChainlinkUniswapV3Oracle.sol @@ -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 - ); - } + {} } diff --git a/contracts/oracles/UniswapV3ChainlinkOracle.sol b/contracts/oracles/UniswapV3ChainlinkOracle.sol index 20db4592..17cdb720 100644 --- a/contracts/oracles/UniswapV3ChainlinkOracle.sol +++ b/contracts/oracles/UniswapV3ChainlinkOracle.sol @@ -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 - ); - } + {} } diff --git a/contracts/oracles/UniswapV3Oracle.sol b/contracts/oracles/UniswapV3Oracle.sol index b64e655c..20d10214 100644 --- a/contracts/oracles/UniswapV3Oracle.sol +++ b/contracts/oracles/UniswapV3Oracle.sol @@ -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) + {} } diff --git a/contracts/oracles/UniswapV3PairOracle.sol b/contracts/oracles/UniswapV3PairOracle.sol index 0079f404..5f1b2d32 100644 --- a/contracts/oracles/UniswapV3PairOracle.sol +++ b/contracts/oracles/UniswapV3PairOracle.sol @@ -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) - ); - } + {} } diff --git a/contracts/oracles/adapters/ChainlinkBorrowableAdapter.sol b/contracts/oracles/adapters/ChainlinkBorrowableAdapter.sol index ef8caf84..46194ed1 100644 --- a/contracts/oracles/adapters/ChainlinkBorrowableAdapter.sol +++ b/contracts/oracles/adapters/ChainlinkBorrowableAdapter.sol @@ -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(); } } diff --git a/contracts/oracles/adapters/ChainlinkCollateralAdapter.sol b/contracts/oracles/adapters/ChainlinkCollateralAdapter.sol index cc901c6c..3488268a 100644 --- a/contracts/oracles/adapters/ChainlinkCollateralAdapter.sol +++ b/contracts/oracles/adapters/ChainlinkCollateralAdapter.sol @@ -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(); } } diff --git a/contracts/oracles/adapters/StaticBorrowableAdapter.sol b/contracts/oracles/adapters/StaticBorrowableAdapter.sol new file mode 100644 index 00000000..ea90b5de --- /dev/null +++ b/contracts/oracles/adapters/StaticBorrowableAdapter.sol @@ -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; + } +} diff --git a/contracts/oracles/adapters/UniswapV3BorrowableAdapter.sol b/contracts/oracles/adapters/UniswapV3BorrowableAdapter.sol index b405a8e0..a3971c24 100644 --- a/contracts/oracles/adapters/UniswapV3BorrowableAdapter.sol +++ b/contracts/oracles/adapters/UniswapV3BorrowableAdapter.sol @@ -3,12 +3,28 @@ pragma solidity ^0.8.0; import {IUniswapV3Pool} from "@uniswap/v3-core/interfaces/IUniswapV3Pool.sol"; -abstract contract UniswapV3BorrowableAdapter { - IUniswapV3Pool public immutable UNI_V3_BORROWABLE_POOL; - uint32 public immutable UNI_V3_BORROWABLE_DELAY; +import {OracleFeed} from "../libraries/OracleFeed.sol"; +import {UniswapV3PoolLib} from "../libraries/UniswapV3PoolLib.sol"; + +import {BaseOracle} from "../BaseOracle.sol"; + +abstract contract UniswapV3BorrowableAdapter is BaseOracle { + using UniswapV3PoolLib for IUniswapV3Pool; + + IUniswapV3Pool private immutable _UNI_V3_BORROWABLE_POOL; + uint32 private immutable _UNI_V3_BORROWABLE_DELAY; constructor(address pool, uint32 delay) { - UNI_V3_BORROWABLE_POOL = IUniswapV3Pool(pool); - UNI_V3_BORROWABLE_DELAY = delay; + _UNI_V3_BORROWABLE_POOL = IUniswapV3Pool(pool); + _UNI_V3_BORROWABLE_DELAY = delay; + BORROWABLE_SCALE = 1e18; + } + + function BORROWABLE_FEED() external view returns (string memory, address) { + return (OracleFeed.UNISWAP_V3, address(_UNI_V3_BORROWABLE_POOL)); + } + + function borrowablePrice() public view virtual override returns (uint256) { + return _UNI_V3_BORROWABLE_POOL.price(_UNI_V3_BORROWABLE_DELAY); } } diff --git a/contracts/oracles/adapters/UniswapV3CollateralAdapter.sol b/contracts/oracles/adapters/UniswapV3CollateralAdapter.sol index e6c67eeb..90975524 100644 --- a/contracts/oracles/adapters/UniswapV3CollateralAdapter.sol +++ b/contracts/oracles/adapters/UniswapV3CollateralAdapter.sol @@ -3,12 +3,28 @@ pragma solidity ^0.8.0; import {IUniswapV3Pool} from "@uniswap/v3-core/interfaces/IUniswapV3Pool.sol"; -abstract contract UniswapV3CollateralAdapter { - IUniswapV3Pool public immutable UNI_V3_COLLATERAL_POOL; - uint32 public immutable UNI_V3_COLLATERAL_DELAY; +import {OracleFeed} from "../libraries/OracleFeed.sol"; +import {UniswapV3PoolLib} from "../libraries/UniswapV3PoolLib.sol"; + +import {BaseOracle} from "../BaseOracle.sol"; + +abstract contract UniswapV3CollateralAdapter is BaseOracle { + using UniswapV3PoolLib for IUniswapV3Pool; + + IUniswapV3Pool private immutable _UNI_V3_COLLATERAL_POOL; + uint32 private immutable _UNI_V3_COLLATERAL_DELAY; constructor(address pool, uint32 delay) { - UNI_V3_COLLATERAL_POOL = IUniswapV3Pool(pool); - UNI_V3_COLLATERAL_DELAY = delay; + _UNI_V3_COLLATERAL_POOL = IUniswapV3Pool(pool); + _UNI_V3_COLLATERAL_DELAY = delay; + COLLATERAL_SCALE = 1e18; + } + + function COLLATERAL_FEED() external view returns (string memory, address) { + return (OracleFeed.UNISWAP_V3, address(_UNI_V3_COLLATERAL_POOL)); + } + + function collateralPrice() public view virtual override returns (uint256) { + return _UNI_V3_COLLATERAL_POOL.price(_UNI_V3_COLLATERAL_DELAY); } } diff --git a/contracts/oracles/interfaces/IOracle.sol b/contracts/oracles/interfaces/IOracle.sol index 505058f2..ded3fb51 100644 --- a/contracts/oracles/interfaces/IOracle.sol +++ b/contracts/oracles/interfaces/IOracle.sol @@ -4,6 +4,11 @@ pragma solidity >=0.5.0; import {IOracle as IBlueOracle} from "@morpho-blue/interfaces/IOracle.sol"; interface IOracle is IBlueOracle { - function FEED_COLLATERAL() external view returns (string memory, address); - function FEED_BORROWABLE() external view returns (string memory, address); + function COLLATERAL_FEED() external view returns (string memory, address); + function BORROWABLE_FEED() external view returns (string memory, address); + + function COLLATERAL_SCALE() external view returns (uint256); + function BORROWABLE_SCALE() external view returns (uint256); + function collateralPrice() external view returns (uint256); + function borrowablePrice() external view returns (uint256); } diff --git a/contracts/oracles/libraries/OracleFeed.sol b/contracts/oracles/libraries/OracleFeed.sol index 3d341a6f..7cae1534 100644 --- a/contracts/oracles/libraries/OracleFeed.sol +++ b/contracts/oracles/libraries/OracleFeed.sol @@ -15,4 +15,6 @@ library OracleFeed { string internal constant RATED = "rated"; string internal constant API3 = "api3"; + + string internal constant STATIC = "static"; } diff --git a/src/bundler/BundleAction.ts b/src/bundler/BundleAction.ts index 03bb6cc7..39ff0219 100644 --- a/src/bundler/BundleAction.ts +++ b/src/bundler/BundleAction.ts @@ -105,7 +105,12 @@ class BundleAction { ]); } - static morphoWithdraw(market: MarketStruct, amount: BigNumberish, shares: BigNumberish, receiver: string): BundleCall { + static morphoWithdraw( + market: MarketStruct, + amount: BigNumberish, + shares: BigNumberish, + receiver: string, + ): BundleCall { return BundleAction.MORPHO_BUNDLER_IFC.encodeFunctionData("morphoWithdraw", [market, amount, shares, receiver]); } diff --git a/test/forge/ChainlinkPairOracle.t.sol b/test/forge/ChainlinkPairOracle.t.sol index 93c39c33..e62e5617 100644 --- a/test/forge/ChainlinkPairOracle.t.sol +++ b/test/forge/ChainlinkPairOracle.t.sol @@ -6,6 +6,7 @@ import "./mocks/ERC20Mock.sol"; import "contracts/oracles/ChainlinkPairOracle.sol"; +import {OracleFeed} from "contracts/oracles/libraries/OracleFeed.sol"; import {FullMath} from "@uniswap/v3-core/libraries/FullMath.sol"; import "@forge-std/console2.sol"; @@ -33,14 +34,19 @@ contract ChainlinkOracleTest is Test { SCALE = 1e26; // 1e36 * 10 ** (8 - 18); - chainlinkOracle = new ChainlinkPairOracle(address(collateralFeed), address(borrowableFeed), SCALE); + chainlinkOracle = new ChainlinkPairOracle(SCALE, address(collateralFeed), address(borrowableFeed)); } function testConfig() public { - assertEq(address(chainlinkOracle.CHAINLINK_COLLATERAL_FEED()), address(collateralFeed)); - assertEq(address(chainlinkOracle.CHAINLINK_BORROWABLE_FEED()), address(borrowableFeed)); - assertEq(chainlinkOracle.CHAINLINK_COLLATERAL_PRICE_SCALE(), 10 ** COLLATERAL_DECIMALS); - assertEq(chainlinkOracle.CHAINLINK_BORROWABLE_PRICE_SCALE(), 10 ** BORROWABLE_DECIMALS); + (string memory collateralOracleFeed, address collateralChainlinkFeed) = chainlinkOracle.COLLATERAL_FEED(); + (string memory borrowableOracleFeed, address borrowableChainlinkFeed) = chainlinkOracle.BORROWABLE_FEED(); + + assertEq(collateralOracleFeed, OracleFeed.CHAINLINK_V3, "collateralOracleFeed"); + assertEq(borrowableOracleFeed, OracleFeed.CHAINLINK_V3, "borrowableOracleFeed"); + assertEq(collateralChainlinkFeed, address(collateralFeed), "collateralChainlinkFeed"); + assertEq(borrowableChainlinkFeed, address(borrowableFeed), "borrowableChainlinkFeed"); + assertEq(chainlinkOracle.COLLATERAL_SCALE(), 10 ** COLLATERAL_DECIMALS); + assertEq(chainlinkOracle.BORROWABLE_SCALE(), 10 ** BORROWABLE_DECIMALS); assertEq(chainlinkOracle.PRICE_SCALE(), SCALE); } @@ -89,7 +95,7 @@ contract ChainlinkOracleTest is Test { ? 1e36 / 10 ** (collateralDecimals - borrowableDecimals) : 1e36 * (borrowableDecimals - collateralDecimals); // 1e36 * 10 ** (borrow decimals - collateral decimals); - chainlinkOracle = new ChainlinkPairOracle(address(collateralFeed), address(borrowableFeed), scale); + chainlinkOracle = new ChainlinkPairOracle(scale, address(collateralFeed), address(borrowableFeed)); assertEq( chainlinkOracle.price(),