Skip to content

Commit

Permalink
feat: deploy-oracle-PT-Dec-maturity (#257)
Browse files Browse the repository at this point in the history
* feat: deploy-oracle-PT-Dec-maturity

* add ezETH market

* fix tests

* fix tests

* deployed Pendle PT LRT oracles

* fix tests

* fix Pendle oracles

* ezETH feed Morpho compatible

* feat: fix PT oracles

* deploy new oracles for PTezETH and PTweETH
  • Loading branch information
GuillaumeNervoXS authored Jun 18, 2024
1 parent 6c077d7 commit 1b128e2
Show file tree
Hide file tree
Showing 35 changed files with 1,083 additions and 109 deletions.
52 changes: 52 additions & 0 deletions broadcast/PTezETHOracle.s.sol/1/run-1718178882.json

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions broadcast/PTezETHOracle.s.sol/1/run-1718179163.json

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions broadcast/PTezETHOracle.s.sol/1/run-1718694630.json

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions broadcast/PTezETHOracle.s.sol/1/run-1718694747.json

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions broadcast/PTezETHOracle.s.sol/1/run-latest.json

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions broadcast/PTweETHOracle.s.sol/1/run-1718178605.json

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions broadcast/PTweETHOracle.s.sol/1/run-1718178658.json

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions broadcast/PTweETHOracle.s.sol/1/run-1718178819.json

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions broadcast/PTweETHOracle.s.sol/1/run-1718179107.json

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions broadcast/PTweETHOracle.s.sol/1/run-1718694502.json

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions broadcast/PTweETHOracle.s.sol/1/run-1718694528.json

Large diffs are not rendered by default.

52 changes: 52 additions & 0 deletions broadcast/PTweETHOracle.s.sol/1/run-1718694611.json

Large diffs are not rendered by default.

50 changes: 50 additions & 0 deletions broadcast/PTweETHOracle.s.sol/1/run-1718694851.json

Large diffs are not rendered by default.

44 changes: 21 additions & 23 deletions broadcast/PTweETHOracle.s.sol/1/run-latest.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions contracts/oracle/BaseFeedPTPendle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ abstract contract BaseFeedPTPendle is AccessControl, AggregatorV3Interface, Base
)
external
view
virtual
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
{
return (0, int256(_getQuoteAmount()), 0, 0, 0);
Expand All @@ -88,6 +89,7 @@ abstract contract BaseFeedPTPendle is AccessControl, AggregatorV3Interface, Base
function latestRoundData()
external
view
virtual
returns (uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound)
{
return (0, int256(_getQuoteAmount()), 0, 0, 0);
Expand Down
10 changes: 5 additions & 5 deletions contracts/oracle/BaseOraclePTPendle.sol
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity ^0.8.12;

import { UNIT, UD60x18, ud } from "prb/math/UD60x18.sol";
import "pendle/interfaces/IPMarket.sol";
import { PendlePtOracleLib } from "pendle/oracles/PendlePtOracleLib.sol";
import { PendlePYOracleLib } from "pendle/oracles/PendlePYOracleLib.sol";
import "../utils/Errors.sol";

/// @title BaseOraclePTPendle
Expand Down Expand Up @@ -34,8 +34,8 @@ abstract contract BaseOraclePTPendle {
modifier onlyGovernorOrGuardian() virtual;

function _getQuoteAmount() internal view virtual returns (uint256) {
uint256 economicalLowerBound = _economicalPTLowerBoundPrice();
uint256 pendlePrice = _pendlePTPrice();
(uint256 pendlePrice, uint256 index) = _pendlePTPrice(IPMarket(market()), twapDuration);
uint256 economicalLowerBound = (_economicalPTLowerBoundPrice() * BASE_18) / index;
uint256 minPrice = economicalLowerBound > pendlePrice ? pendlePrice : economicalLowerBound;
uint256 quote = (_detectHackRatio() * minPrice) / BASE_18;
return quote;
Expand Down Expand Up @@ -69,8 +69,8 @@ abstract contract BaseOraclePTPendle {
/// - getPtToSy() should be used if the underlying token is tradable,
/// - getPtToAsset() if not
/// @dev https://docs.pendle.finance/Developers/Contracts/StandardizedYield#asset-of-sy--assetinfo-function
function _pendlePTPrice() internal view virtual returns (uint256) {
return PendlePtOracleLib.getPtToAssetRate(IPMarket(market()), twapDuration);
function _pendlePTPrice(IPMarket _market, uint32 _twapDuration) internal view virtual returns (uint256, uint256) {
return (PendlePYOracleLib.getPtToAssetRate(_market, _twapDuration), BASE_18);
}

function _detectHackRatio() internal view returns (uint256) {
Expand Down
26 changes: 26 additions & 0 deletions contracts/oracle/FeedPTForSY.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.12;

import { PendlePYOracleLib, PMath } from "pendle/oracles/PendlePYOracleLib.sol";
import "pendle/interfaces/IPMarket.sol";

/// @title FeedPTForSY
/// @author Angle Labs, Inc.
/// @notice Override the BaseFeedPTPendle to provide the price of PT tokens based on the ibToken and not the underlying token
abstract contract FeedPTForSY {
using PMath for uint256;

/// @dev Depending on the market you should use
/// - getPtToSy() should be used if the underlying token is tradable,
/// - getPtToAsset() if not
/// @dev https://docs.pendle.finance/Developers/Contracts/StandardizedYield#asset-of-sy--assetinfo-function
function _pendlePTPrice(IPMarket _market, uint32 _twapDuration) internal view virtual returns (uint256, uint256) {
(uint256 syIndex, uint256 pyIndex) = PendlePYOracleLib.getSYandPYIndexCurrent(_market);
if (syIndex >= pyIndex) {
return (PendlePYOracleLib.getPtToAssetRateRaw(_market, _twapDuration).divDown(syIndex), syIndex);
} else {
return (PendlePYOracleLib.getPtToAssetRateRaw(_market, _twapDuration).divDown(pyIndex), syIndex);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ contract OraclePTweETHEUR is BaseOracleChainlinkMultiTwoFeeds, BaseOraclePTPendl
/// @inheritdoc IOracle
function circuitChainlink() public pure override returns (AggregatorV3Interface[] memory) {
AggregatorV3Interface[] memory _circuitChainlink = new AggregatorV3Interface[](2);
// Oracle weETH/USD
_circuitChainlink[0] = AggregatorV3Interface(0xdDb6F90fFb4d3257dd666b69178e5B3c5Bf41136);
// Oracle ETH/USD
_circuitChainlink[0] = AggregatorV3Interface(0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419);
// Oracle EUR/USD
_circuitChainlink[1] = AggregatorV3Interface(0xb49f677943BC038e9857d61E7d053CaA2C1734C1);
return _circuitChainlink;
Expand Down
41 changes: 41 additions & 0 deletions contracts/oracle/morpho/mainnet/MorphoFeedPTezETHDec24.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.12;

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

import "../../BaseFeedPTPendle.sol";
import "../../FeedPTForSY.sol";

/// @title MorphoFeedPTezETHDec24
/// @author Angle Labs, Inc.
/// @notice Gives the price of PT-ezETH in ETH in base 18
contract MorphoFeedPTezETHDec24 is BaseFeedPTPendle {
string public constant description = "PT-ezETH/ETH Oracle";

Check warning on line 14 in contracts/oracle/morpho/mainnet/MorphoFeedPTezETHDec24.sol

View workflow job for this annotation

GitHub Actions / lint

Constant name must be in capitalized SNAKE_CASE

constructor(
IAccessControlManager accessControlManager,
uint256 _maxImpliedRate,
uint32 _twapDuration
) BaseFeedPTPendle(accessControlManager, _maxImpliedRate, _twapDuration) {}

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OVERRIDES
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

function asset() public pure override returns (address) {
return 0xbf5495Efe5DB9ce00f80364C8B423567e58d2110;
}

function sy() public pure override returns (address) {
return 0x22E12A50e3ca49FB183074235cB1db84Fe4C716D;
}

function maturity() public pure override returns (uint256) {
return 1735171200;
}

function market() public pure override returns (address) {
return 0xD8F12bCDE578c653014F27379a6114F67F0e445f;
}
}
3 changes: 1 addition & 2 deletions contracts/oracle/morpho/mainnet/MorphoFeedPTweETH.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import "../../BaseFeedPTPendle.sol";
/// @author Angle Labs, Inc.
/// @notice Gives the price of PT-weETH in ETH in base 18
contract MorphoFeedPTweETH is BaseFeedPTPendle {
string public constant description = "PT-weETH/weETH Oracle";
string public constant description = "PT-weETH/ETH Oracle";

Check warning on line 13 in contracts/oracle/morpho/mainnet/MorphoFeedPTweETH.sol

View workflow job for this annotation

GitHub Actions / lint

Constant name must be in capitalized SNAKE_CASE

constructor(
IAccessControlManager accessControlManager,
Expand All @@ -21,7 +21,6 @@ contract MorphoFeedPTweETH is BaseFeedPTPendle {
/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OVERRIDES
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

function asset() public pure override returns (address) {
return 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;
}
Expand Down
40 changes: 40 additions & 0 deletions contracts/oracle/morpho/mainnet/MorphoFeedPTweETHDec24.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: GPL-3.0

pragma solidity ^0.8.12;

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

import "../../BaseFeedPTPendle.sol";

/// @title MorphoFeedPTweETH
/// @author Angle Labs, Inc.
/// @notice Gives the price of PT-weETH in ETH in base 18
contract MorphoFeedPTweETHDec24 is BaseFeedPTPendle {
string public constant description = "PT-weETH/ETH Oracle";

Check warning on line 13 in contracts/oracle/morpho/mainnet/MorphoFeedPTweETHDec24.sol

View workflow job for this annotation

GitHub Actions / lint

Constant name must be in capitalized SNAKE_CASE

constructor(
IAccessControlManager accessControlManager,
uint256 _maxImpliedRate,
uint32 _twapDuration
) BaseFeedPTPendle(accessControlManager, _maxImpliedRate, _twapDuration) {}

/*//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
OVERRIDES
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////*/

function asset() public pure override returns (address) {
return 0xCd5fE23C85820F7B72D0926FC9b05b43E359b7ee;
}

function sy() public pure override returns (address) {
return 0xAC0047886a985071476a1186bE89222659970d65;
}

function maturity() public pure override returns (uint256) {
return 1735171200;
}

function market() public pure override returns (address) {
return 0x7d372819240D14fB477f17b964f95F33BeB4c704;
}
}
2 changes: 1 addition & 1 deletion lib/pendle-core-v2-public
2 changes: 1 addition & 1 deletion lib/utils
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"hardhat:compile": "hardhat compile",
"foundry:compile": "forge build",
"deploy": "forge script --skip test --broadcast --verify --slow -vvvv --rpc-url",
"deploy:fork": "FOUNDRY_PROFILE=dev forge script --skip test --slow --fork-url fork --broadcast -vvvv",
"deploy:fork": "forge script --skip test --slow --fork-url fork --broadcast -vvvv",
"check-upgradeability": "hardhat run scripts/upgradeability.ts",
"coverage": "hardhat coverage",
"coverage:foundry": "forge coverage --report lcov",
Expand Down
34 changes: 34 additions & 0 deletions scripts/foundry/mainnet/PTezETHOracle.s.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.17;

import "forge-std/Script.sol";
import { console } from "forge-std/console.sol";
import { MorphoFeedPTezETHDec24 } from "borrow-contracts/oracle/morpho/mainnet/MorphoFeedPTezETHDec24.sol";
import "utils/src/CommonUtils.sol";
import { IAccessControlManager } from "borrow-contracts/interfaces/IAccessControlManager.sol";

contract PTezETHOracleDeploy is Script, CommonUtils {
function run() external {
uint256 deployerPrivateKey = vm.envUint("DEPLOYER_PRIVATE_KEY");
address deployer = vm.addr(deployerPrivateKey);
vm.startBroadcast(deployerPrivateKey);

// TODO
uint256 chainId = CHAIN_ETHEREUM;
address coreBorrow = _chainToContract(chainId, ContractType.CoreBorrow);
uint32 _TWAP_DURATION = 30 minutes;
uint256 _MAX_IMPLIED_RATE = 0.25 ether;
// end TODO

MorphoFeedPTezETHDec24 oracle = new MorphoFeedPTezETHDec24(
IAccessControlManager(address(coreBorrow)),
_MAX_IMPLIED_RATE,
_TWAP_DURATION
);
(, int256 answer, , , ) = oracle.latestRoundData();
console.log("oracle value ", uint256(answer));
console.log("Successfully deployed PT-ezETH: ", address(oracle));

vm.stopBroadcast();
}
}
8 changes: 4 additions & 4 deletions scripts/foundry/mainnet/PTweETHOracle.s.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.17;

import "forge-std/Script.sol";
import { console } from "forge-std/console.sol";
import { MorphoFeedPTweETH } from "borrow-contracts/oracle/morpho/mainnet/MorphoFeedPTweETH.sol";
import { MorphoFeedPTweETHDec24 } from "borrow-contracts/oracle/morpho/mainnet/MorphoFeedPTweETHDec24.sol";
import "utils/src/CommonUtils.sol";
import { IAccessControlManager } from "borrow-contracts/interfaces/IAccessControlManager.sol";

Expand All @@ -15,12 +15,12 @@ contract PTweETHOracleDeploy is Script, CommonUtils {

// TODO
uint256 chainId = CHAIN_ETHEREUM;
address coreBorrow = 0x5bc6BEf80DA563EBf6Df6D6913513fa9A7ec89BE;
address coreBorrow = _chainToContract(chainId, ContractType.CoreBorrow);
uint32 _TWAP_DURATION = 30 minutes;
uint256 _MAX_IMPLIED_RATE = 0.5 ether;
uint256 _MAX_IMPLIED_RATE = 0.25 ether;
// end TODO

MorphoFeedPTweETH oracle = new MorphoFeedPTweETH(
MorphoFeedPTweETHDec24 oracle = new MorphoFeedPTweETHDec24(
IAccessControlManager(address(coreBorrow)),
_MAX_IMPLIED_RATE,
_TWAP_DURATION
Expand Down
7 changes: 1 addition & 6 deletions test/foundry/oracles/morpho/MorphoChainlinkOracleTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { IMorphoChainlinkOracleV2 } from "borrow-contracts/interfaces/external/m
import { IAccessControlManager } from "borrow-contracts/interfaces/IAccessControlManager.sol";
import "borrow-contracts/utils/Errors.sol" as Errors;
import "borrow-contracts/mock/MockCoreBorrow.sol";
import { PendlePtOracleLib } from "pendle/oracles/PendlePtOracleLib.sol";
import { IPMarket } from "pendle/interfaces/IPMarket.sol";
import "utils/src/Constants.sol";
import "@chainlink/contracts/src/v0.8/interfaces/AggregatorV3Interface.sol";
Expand All @@ -21,14 +20,10 @@ import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20Metadata } from "@openzeppelin/contracts/token/ERC20/extensions/IERC20Metadata.sol";
import { CommonUtils } from "utils/src/CommonUtils.sol";
import { IERC4626 } from "borrow-contracts/interfaces/external/IERC4626.sol";
import { PendlePtOracleLib } from "pendle/oracles/PendlePtOracleLib.sol";

contract MorphoChainlinkOracleTest is Test, CommonUtils {
using stdStorage for StdStorage;

mapping(uint256 => uint256) internal forkIdentifier;
uint256 public ethereumFork;

address internal _alice = address(uint160(uint256(keccak256(abi.encodePacked("alice")))));
address internal _governor = address(uint160(uint256(keccak256(abi.encodePacked("governor")))));
address internal _guardian = address(uint160(uint256(keccak256(abi.encodePacked("guardian")))));
Expand All @@ -52,7 +47,7 @@ contract MorphoChainlinkOracleTest is Test, CommonUtils {

function setUp() public {
uint256 chainId = CHAIN_ETHEREUM;
ethereumFork = vm.createFork(vm.envString("ETH_NODE_URI_ETHEREUM"));
ethereumFork = vm.createFork(vm.envString("ETH_NODE_URI_ETHEREUM"), 19739302);
forkIdentifier[CHAIN_ETHEREUM] = ethereumFork;

_TWAP_DURATION = 15 minutes;
Expand Down
Loading

0 comments on commit 1b128e2

Please sign in to comment.