Skip to content

Commit 505d8b1

Browse files
authored
Merge pull request #271 from VenusProtocol/develop
New release
2 parents 571a8b0 + e89efe2 commit 505d8b1

File tree

41 files changed

+13650
-2095
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+13650
-2095
lines changed

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,28 @@
1+
## [2.12.0-dev.2](https://github.com/VenusProtocol/oracle/compare/v2.12.0-dev.1...v2.12.0-dev.2) (2025-02-21)
2+
3+
4+
### Features
5+
6+
* add deployments for Pendle oracles used as a reference ([39e82df](https://github.com/VenusProtocol/oracle/commit/39e82df3b40de2031e73176289abd9b4d396a701))
7+
* updating deployment files ([eb9cee1](https://github.com/VenusProtocol/oracle/commit/eb9cee1879960e95b7bfc6c93c7c6092a6f7e3f9))
8+
9+
## [2.12.0-dev.1](https://github.com/VenusProtocol/oracle/compare/v2.11.0...v2.12.0-dev.1) (2025-02-21)
10+
11+
12+
### Features
13+
14+
* add reference oracle conract ([cfa31eb](https://github.com/VenusProtocol/oracle/commit/cfa31eb97a956fc914daa6fd3ff0dd7b31aadd3c))
15+
* add reference oracle deployment for bsc and eth ([0f0cc33](https://github.com/VenusProtocol/oracle/commit/0f0cc33fa90ff85fb475dd046fa6f4ef8f7fcd4a))
16+
* add testnet tags and helpers to dispatch testnets ([8576fe9](https://github.com/VenusProtocol/oracle/commit/8576fe961dc65805ad50617d705748cdca03945d))
17+
* replace multisig with timelock on Ethereum ([6bbff81](https://github.com/VenusProtocol/oracle/commit/6bbff818a8db2869ea630dd0fee34b82b4f1b2f5))
18+
* support compiling for cancun ([5a22e67](https://github.com/VenusProtocol/oracle/commit/5a22e6754daeea2a9c759bec02dfb62457384b02))
19+
* updating deployment files ([9f378c5](https://github.com/VenusProtocol/oracle/commit/9f378c53caf231cc6120c6c671a3c1ad886a19e3))
20+
21+
22+
### Bug Fixes
23+
24+
* patch smock package to check if provider has init ([2f86269](https://github.com/VenusProtocol/oracle/commit/2f86269c94f370f3841d851a7f6f965584b9f66b))
25+
126
## [2.11.0](https://github.com/VenusProtocol/oracle/compare/v2.10.0...v2.11.0) (2025-02-14)
227

328

contracts/ReferenceOracle.sol

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// SPDX-License-Identifier: BSD-3-Clause
2+
// SPDX-FileCopyrightText: 2025 Venus
3+
pragma solidity 0.8.25;
4+
5+
import { Ownable2StepUpgradeable } from "@openzeppelin/contracts-upgradeable/access/Ownable2StepUpgradeable.sol";
6+
import { ensureNonzeroAddress } from "@venusprotocol/solidity-utilities/contracts/validators.sol";
7+
import { ResilientOracleInterface, OracleInterface } from "./interfaces/OracleInterface.sol";
8+
9+
/**
10+
* @title ReferenceOracle
11+
* @author Venus
12+
* @notice Reference oracle is the oracle that is not used for production but required for
13+
* price monitoring. This oracle contains some extra configurations for assets required to
14+
* compute reference prices of their derivative assets (OneJump, ERC4626, Pendle, etc.)
15+
*/
16+
contract ReferenceOracle is Ownable2StepUpgradeable, OracleInterface {
17+
struct ExternalPrice {
18+
/// @notice asset address
19+
address asset;
20+
/// @notice price of the asset from an external source
21+
uint256 price;
22+
}
23+
24+
/// @notice Slot to temporarily store price information from external sources
25+
/// like CMC/Coingecko, useful to compute prices of derivative assets based on
26+
/// prices of the base assets with no on chain price information
27+
bytes32 public constant PRICES_SLOT = keccak256(abi.encode("venus-protocol/oracle/ReferenceOracle/prices"));
28+
29+
/// @notice Resilient oracle address
30+
/// @custom:oz-upgrades-unsafe-allow state-variable-immutable
31+
ResilientOracleInterface public immutable RESILIENT_ORACLE;
32+
33+
/// @notice Oracle configuration for assets
34+
mapping(address => OracleInterface) public oracles;
35+
36+
/// @notice Event emitted when an oracle is set
37+
event OracleConfigured(address indexed asset, address indexed oracle);
38+
39+
/**
40+
* @notice Constructor for the implementation contract. Sets immutable variables.
41+
* @param resilientOracle Resilient oracle address
42+
* @custom:error ZeroAddressNotAllowed is thrown if resilient oracle address is null
43+
* @custom:oz-upgrades-unsafe-allow constructor
44+
*/
45+
constructor(ResilientOracleInterface resilientOracle) {
46+
ensureNonzeroAddress(address(resilientOracle));
47+
RESILIENT_ORACLE = resilientOracle;
48+
_disableInitializers();
49+
}
50+
51+
/**
52+
* @notice Initializes the contract admin
53+
*/
54+
function initialize() external initializer {
55+
__Ownable2Step_init();
56+
}
57+
58+
/**
59+
* @notice Sets an oracle to use for a specific asset
60+
* @dev The production resilientOracle will be used if zero address is passed
61+
* @param asset Asset address
62+
* @param oracle Oracle address
63+
* @custom:access Only owner
64+
* @custom:error ZeroAddressNotAllowed is thrown if asset address is null
65+
* @custom:event Emits OracleConfigured event
66+
*/
67+
function setOracle(address asset, OracleInterface oracle) external onlyOwner {
68+
ensureNonzeroAddress(asset);
69+
oracles[asset] = OracleInterface(oracle);
70+
emit OracleConfigured(asset, address(oracle));
71+
}
72+
73+
/**
74+
* @notice Gets price of the asset assuming other assets have the defined price
75+
* @param asset asset address
76+
* @param externalPrices an array of prices for other assets
77+
* @return USD price in scaled decimal places
78+
*/
79+
function getPriceAssuming(address asset, ExternalPrice[] memory externalPrices) external returns (uint256) {
80+
uint256 externalPricesCount = externalPrices.length;
81+
for (uint256 i = 0; i < externalPricesCount; ++i) {
82+
_storeExternalPrice(externalPrices[i].asset, externalPrices[i].price);
83+
}
84+
return _getPrice(asset);
85+
}
86+
87+
/**
88+
* @notice Gets price of the asset
89+
* @param asset asset address
90+
* @return USD price in scaled decimal places
91+
*/
92+
function getPrice(address asset) external view override returns (uint256) {
93+
return _getPrice(asset);
94+
}
95+
96+
function _storeExternalPrice(address asset, uint256 price) internal {
97+
bytes32 slot = keccak256(abi.encode(PRICES_SLOT, asset));
98+
// solhint-disable-next-line no-inline-assembly
99+
assembly ("memory-safe") {
100+
tstore(slot, price)
101+
}
102+
}
103+
104+
function _getPrice(address asset) internal view returns (uint256) {
105+
uint256 externalPrice = _loadExternalPrice(asset);
106+
if (externalPrice != 0) {
107+
return externalPrice;
108+
}
109+
OracleInterface oracle = oracles[asset];
110+
if (oracle != OracleInterface(address(0))) {
111+
return oracle.getPrice(asset);
112+
}
113+
return RESILIENT_ORACLE.getPrice(asset);
114+
}
115+
116+
function _loadExternalPrice(address asset) internal view returns (uint256 value) {
117+
bytes32 slot = keccak256(abi.encode(PRICES_SLOT, asset));
118+
// solhint-disable-next-line no-inline-assembly
119+
assembly ("memory-safe") {
120+
value := tload(slot)
121+
}
122+
}
123+
}

deploy/16-deploy-SolvBTC.BBN-pendle-oracles.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ import { DeployFunction } from "hardhat-deploy/dist/types";
33
import { HardhatRuntimeEnvironment } from "hardhat/types";
44

55
import { ADDRESSES } from "../helpers/deploymentConfig";
6+
import { isMainnet } from "../helpers/deploymentUtils";
67

78
enum PendleRateKind {
89
PT_TO_ASSET = 0,
@@ -53,6 +54,34 @@ const func: DeployFunction = async ({ getNamedAccounts, deployments, network }:
5354
},
5455
skipIfAlreadyDeployed: true,
5556
});
57+
58+
if (isMainnet(network)) {
59+
const referenceOracle = await ethers.getContract("ReferenceOracle");
60+
const { devMultisig } = addresses;
61+
await deploy("PendleOracle-PT-SolvBTC.BBN-27MAR2025_Reference_PtToAsset", {
62+
contract: "PendleOracle",
63+
from: deployer,
64+
log: true,
65+
deterministicDeployment: false,
66+
args: [
67+
addresses["PT-SolvBTC.BBN-27MAR2025_Market"] || "0x0000000000000000000000000000000000000001",
68+
ptOracleAddress,
69+
PendleRateKind.PT_TO_ASSET,
70+
addresses["PT-SolvBTC.BBN-27MAR2025"],
71+
addresses.BTCB,
72+
referenceOracle.address,
73+
900,
74+
],
75+
proxy: {
76+
owner: devMultisig,
77+
proxyContract: "OptimizedTransparentUpgradeableProxy",
78+
viaAdminContract: {
79+
name: "DevProxyAdmin",
80+
},
81+
},
82+
skipIfAlreadyDeployed: true,
83+
});
84+
}
5685
};
5786

5887
export default func;
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import hre from "hardhat";
2+
import { DeployFunction } from "hardhat-deploy/dist/types";
3+
import { HardhatRuntimeEnvironment } from "hardhat/types";
4+
5+
import { ADDRESSES } from "../helpers/deploymentConfig";
6+
import { skipAllExcept } from "../helpers/deploymentUtils";
7+
8+
const func: DeployFunction = async function ({ getNamedAccounts, deployments, network }: HardhatRuntimeEnvironment) {
9+
const { deploy } = deployments;
10+
const { deployer } = await getNamedAccounts();
11+
12+
const devMultisig = network.live ? ADDRESSES[network.name].devMultisig : deployer;
13+
const proxyAdminArtifact = await hre.artifacts.readArtifact(
14+
"hardhat-deploy/solc_0.8/openzeppelin/proxy/transparent/ProxyAdmin.sol:ProxyAdmin",
15+
);
16+
17+
const resilientOracle = await hre.ethers.getContract("ResilientOracle");
18+
19+
await deploy("ReferenceOracle", {
20+
contract: "ReferenceOracle",
21+
from: deployer,
22+
log: true,
23+
deterministicDeployment: false,
24+
skipIfAlreadyDeployed: true,
25+
args: [resilientOracle.address],
26+
proxy: {
27+
owner: devMultisig,
28+
proxyContract: "OptimizedTransparentUpgradeableProxy",
29+
execute: {
30+
methodName: "initialize",
31+
args: [],
32+
},
33+
viaAdminContract: {
34+
name: "DevProxyAdmin",
35+
artifact: proxyAdminArtifact,
36+
},
37+
},
38+
});
39+
40+
const devProxyAdmin = await hre.ethers.getContract("DevProxyAdmin");
41+
const devProxyAdminOwner = await devProxyAdmin.owner();
42+
43+
if (devProxyAdminOwner === deployer) {
44+
await devProxyAdmin.transferOwnership(devMultisig);
45+
console.log(`Ownership of DevProxyAdmin transfered from deployer to dev multisig (${devMultisig})`);
46+
}
47+
48+
const referenceOracle = await hre.ethers.getContract("ReferenceOracle");
49+
const referenceOracleOwner = await referenceOracle.owner();
50+
51+
if (referenceOracleOwner === deployer) {
52+
await referenceOracle.transferOwnership(devMultisig);
53+
console.log(`Ownership of ReferenceOracle transfered from deployer to dev multisig (${devMultisig})`);
54+
}
55+
};
56+
57+
export default func;
58+
func.skip = skipAllExcept(["bscmainnet", "ethereum"]);
59+
func.tags = ["reference"];

0 commit comments

Comments
 (0)