Diff
checker
टेक्स्ट
टेक्स्ट
छवियां
दस्तावेज़
Excel
फ़ोल्डर्स
Legal
Enterprise
डेस्कटॉप
मूल्य
साइन इन करें
Diffchecker डेस्कटॉप डाउनलोड करें
टेक्स्ट की तुलना करें
दो टेक्स्ट फ़ाइलों के बीच अंतर ढूंढें
उपकरण
इतिहास
प्रदर्शन
लेआउट
विभाजित
संयुक्त
रियल-टाइम एडिटर
रिक्त स्थान छिपाएँ
अपरिवर्तित संक्षिप्त करें
लाइन रैप बंद
परिवर्तन हाइलाइट करें
स्मार्ट
सिंटैक्स
कोई नहीं
दिखावट बदलें
प्रोसेसिंग
अनदेखा करें
टेक्स्ट बदलें
पहले अंतर पर जाएँ
इनपुट संपादित करें
Diffchecker Desktop
Diffchecker चलाने का सबसे सुरक्षित तरीका। Diffchecker Desktop ऐप पाएं: आपके diffs कभी आपके कंप्यूटर से बाहर नहीं जाते!
Desktop पाएं
LRTOracle
बनाया गया
12 माह पहले
Diff कभी समाप्त नहीं होता
साफ़
निर्यात करें
शेयर करें
समझाएं
68 हटाए गए
लाइनें
कुल
हटाया गया
अक्षर
कुल
हटाया गया
इस सुविधा का उपयोग जारी रखने के लिए, अपग्रेड करें
Diff
checker
Pro
मूल्य देखें
215 लाइनें
सभी को कॉपी करें
180 जोड़े गए
लाइनें
कुल
जोड़ा गया
अक्षर
कुल
जोड़ा गया
इस सुविधा का उपयोग जारी रखने के लिए, अपग्रेड करें
Diff
checker
Pro
मूल्य देखें
317 लाइनें
सभी को कॉपी करें
// SPDX-License-Identifier: BUSL-1.1
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.27;
pragma solidity 0.8.27;
import { UtilLib } from "./utils/UtilLib.sol";
import { UtilLib } from "./utils/UtilLib.sol";
import { LRTConstants } from "./utils/LRTConstants.sol";
import { LRTConstants } from "./utils/LRTConstants.sol";
import { LRTConfigRoleChecker, ILRTConfig } from "./utils/LRTConfigRoleChecker.sol";
import { LRTConfigRoleChecker, ILRTConfig } from "./utils/LRTConfigRoleChecker.sol";
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
import { WadMath } from "./utils/WadMath.sol";
import { IRSETH } from "./interfaces/IRSETH.sol";
import { IRSETH } from "./interfaces/IRSETH.sol";
import { IPriceFetcher } from "./interfaces/IPriceFetcher.sol";
import { IPriceFetcher } from "./interfaces/IPriceFetcher.sol";
import { ILRTOracle } from "./interfaces/ILRTOracle.sol";
import { ILRTOracle } from "./interfaces/ILRTOracle.sol";
import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol";
import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol";
import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";
import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol";
interface IPausable {
interface IPausable {
function pause() external;
function pause() external;
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
function paused() external view returns (bool);
}
}
/// @title LRTOracle Contract
/// @title LRTOracle Contract
/// @notice oracle contract that calculates the exchange rate of assets
/// @notice oracle contract that calculates the exchange rate of assets
contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, Initializable {
contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, Initializable {
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
using WadMath for uint256;
mapping(address asset => address priceOracle) public override assetPriceOracle;
mapping(address asset => address priceOracle) public override assetPriceOracle;
uint256 public override rsETHPrice;
uint256 public override rsETHPrice;
uint256 public pricePercentageLimit;
uint256 public pricePercentageLimit;
uint256 public highestRsethPrice;
uint256 public highestRsethPrice;
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
//
legacy
variables
//
Daily fee minting limit
variables
uint256 public
legacy_cooldownPeriodInTimestamp
;
uint256 public
currentPeriodMintedFeeAmount;
uint256 public
legacy_lastUpdatedCoolDownTimestamp;
uint256 public feePeriodStartTime
;
uint256 public
maxFeeMintAmountPerDay;
/// @notice New variable added for pausable functionality
bool public paused;
modifier onlySupportedOracle(address asset) {
modifier onlySupportedOracle(address asset) {
if (assetPriceOracle[asset] == address(0)) {
if (assetPriceOracle[asset] == address(0)) {
revert AssetOracleNotSupported();
revert AssetOracleNotSupported();
}
}
_;
_;
}
}
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
modifier whenNotPaused() {
if (paused) revert ContractPaused();
_;
}
modifier whenPaused() {
if (!paused) revert ContractNotPaused();
_;
}
/// @custom:oz-upgrades-unsafe-allow constructor
/// @custom:oz-upgrades-unsafe-allow constructor
constructor() {
constructor() {
_disableInitializers();
_disableInitializers();
}
}
/// @dev Initializes the contract
/// @dev Initializes the contract
/// @param lrtConfigAddr LRT config address
/// @param lrtConfigAddr LRT config address
function initialize(address lrtConfigAddr) external initializer {
function initialize(address lrtConfigAddr) external initializer {
UtilLib.checkNonZeroAddress(lrtConfigAddr);
UtilLib.checkNonZeroAddress(lrtConfigAddr);
lrtConfig = ILRTConfig(lrtConfigAddr);
lrtConfig = ILRTConfig(lrtConfigAddr);
emit UpdatedLRTConfig(lrtConfigAddr);
emit UpdatedLRTConfig(lrtConfigAddr);
}
}
/*//////////////////////////////////////////////////////////////
/*//////////////////////////////////////////////////////////////
write functions
write functions
//////////////////////////////////////////////////////////////*/
//////////////////////////////////////////////////////////////*/
/// @notice updates RSETH/ETH exchange rate
/// @notice updates RSETH/ETH exchange rate
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
/// @dev calculates
based on stakedAsset value received from
eigen layer
/// @dev calculates
rsETH price
based on stakedAsset value received from
EigenLayer
function updateRSETHPrice
() public {
function updateRSETHPrice() public whenNotPaused {
_updateRsETHPrice();
}
/// @dev update rsETH price as an manager account
/// @dev main benefit is to be able to update the price in case of the price going above the threshold
/// @dev only LRT manager is allowed to call this function
function updateRSETHPrice
AsManager() external onlyLRTManager {
_updateRsETHPrice();
}
/// @dev add/update the price oracle of any asset
/// @dev only onlyLRTAdmin is allowed
/// @param asset asset address for which oracle price needs to be added/updated
function updatePriceOracleForValidated(address asset, address priceOracle) external onlyLRTAdmin {
// Sanity check: oracle price must have precision between 1e16 and 1e19
uint256 price = IPriceFetcher(priceOracle).getAssetPrice(asset);
if (price > 1e19 || price < 1e16) {
revert InvalidPriceOracle();
}
updatePriceOracleFor(asset, priceOracle);
}
/// @dev add/update the price oracle of any asset
/// @dev only onlyLRTAdmin is allowed
/// @param asset asset address for which oracle price needs to be added/updated
function updatePriceOracleFor(address asset, address priceOracle) public onlyLRTAdmin {
if (lrtConfig.isSupportedAsset(asset)) {
UtilLib.checkNonZeroAddress(priceOracle);
}
Text moved from lines 168-180
assetPriceOracle[asset] = priceOracle;
emit AssetPriceOracleUpdate(asset, priceOracle);
}
/// @dev set the price percentage limit. Only onlyLRTAdmin is allowed
/// @dev PricePercentageLimit for 1% is 1e16
/// @dev Price Percentage Limit for 100% is 1e18
/// @param _pricePercentageLimit price percentage limit
function setPricePercentageLimit(uint256 _pricePercentageLimit) external onlyLRTAdmin {
pricePercentageLimit = _pricePercentageLimit;
emit PricePercentageLimitUpdate(_pricePercentageLimit);
}
/// @dev set the maximum fee minting amount per day. Only onlyLRTManager is allowed
/// @param _maxFeeMintAmountPerDay maximum amount of fee that can be minted per day
function setMaxFeeMintAmountPerDay(uint256 _maxFeeMintAmountPerDay) external onlyLRTManager {
maxFeeMintAmountPerDay = _maxFeeMintAmountPerDay;
emit MaxFeeMintAmountPerDayUpdated(_maxFeeMintAmountPerDay);
}
/// @dev Pauses the pausable methods in the contract
function pause() external onlyLRTManager whenNotPaused {
_pause();
}
/// @dev Unpauses the pausable methods in the contract
function unpause() external onlyLRTAdmin whenPaused {
paused = false;
emit Unpaused(msg.sender);
}
/*//////////////////////////////////////////////////////////////
view functions
//////////////////////////////////////////////////////////////*/
/// @notice Provides Asset/ETH exchange rate
/// @dev reads from priceFetcher interface which may fetch price from any supported oracle
/// @param asset the asset for which exchange rate is required
/// @return assetPrice exchange rate of asset
function getAssetPrice(address asset) public view onlySupportedOracle(asset) returns (uint256) {
return IPriceFetcher(assetPriceOracle[asset]).getAssetPrice(asset);
}
/*//////////////////////////////////////////////////////////////
internal functions
//////////////////////////////////////////////////////////////*/
/// @dev Checks and updates daily fee minting limits
/// @param feeAmount The amount of fee to be minted
function _checkAndUpdateDailyFeeMintLimit(uint256 feeAmount) internal {
// Reset or initialize the period if it's unset or a day has passed
if (feePeriodStartTime == 0 || block.timestamp >= feePeriodStartTime + 1 days) {
currentPeriodMintedFeeAmount = 0;
feePeriodStartTime = block.timestamp;
}
// Check if minting would exceed the daily limit
if (currentPeriodMintedFeeAmount + feeAmount > maxFeeMintAmountPerDay) {
revert DailyFeeMintLimitExceeded(currentPeriodMintedFeeAmount + feeAmount, maxFeeMintAmountPerDay);
}
currentPeriodMintedFeeAmount += feeAmount;
}
/// @dev Internal function to update rsETH price
// solhint-disable-next-line code-complexity
function _updateRsETHPrice() internal {
address rsETHTokenAddress = lrtConfig.rsETH();
address rsETHTokenAddress = lrtConfig.rsETH();
uint256 rsethSupply = IRSETH(rsETHTokenAddress).totalSupply();
uint256 rsethSupply = IRSETH(rsETHTokenAddress).totalSupply();
if (rsethSupply == 0) {
if (rsethSupply == 0) {
rsETHPrice = 1 ether;
rsETHPrice = 1 ether;
highestRsethPrice = 1 ether;
highestRsethPrice = 1 ether;
return;
return;
}
}
if (highestRsethPrice == 0) {
if (highestRsethPrice == 0) {
highestRsethPrice = rsETHPrice;
highestRsethPrice = rsETHPrice;
}
}
uint256 previousPrice = rsETHPrice;
uint256 previousPrice = rsETHPrice;
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
// get total ETH in the protocol
// get total ETH in the protocol
(normalized to 1e18)
uint256 totalETHInProtocol = _getTotalEthInProtocol();
uint256 totalETHInProtocol = _getTotalEthInProtocol();
// calculate previousTVL using rsethSupply multiplied by rsETHPrice
// calculate previousTVL using rsethSupply multiplied by rsETHPrice
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
uint256 previousTVL = rsethSupply
*
rsETHPrice
;
uint256 previousTVL = rsethSupply
.mulWad(
rsETHPrice
)
;
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
// only take fee if TVL increased
IPausable lrtDepositPool = IPausable(lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL));
IPausable withdrawalManager = IPausable(lrtConfig.getContract(LRTConstants.LRT_WITHDRAW_MANAGER));
// determine if the protocol is active (not paused)
bool protocolPaused = lrtDepositPool.paused() || withdrawalManager.paused() || paused;
// only take fee if TVL increased
and protocol is not paused
uint256 protocolFeeInETH = 0;
uint256 protocolFeeInETH = 0;
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
if (
totalETHInProtocol > previousTVL) {
if (
!protocolPaused &&
totalETHInProtocol > previousTVL) {
uint256 rewardAmount = totalETHInProtocol - previousTVL;
uint256 rewardAmount = totalETHInProtocol - previousTVL;
protocolFeeInETH = (rewardAmount * lrtConfig.protocolFeeInBPS()) / 10_000;
protocolFeeInETH = (rewardAmount * lrtConfig.protocolFeeInBPS()) / 10_000;
}
}
// compute new rsETH price based on total ETH minus fee
// compute new rsETH price based on total ETH minus fee
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
uint256 newRsETHPrice = (totalETHInProtocol - protocolFeeInETH)
/
rsethSupply
;
uint256 newRsETHPrice = (totalETHInProtocol - protocolFeeInETH)
.divWad(
rsethSupply
)
;
if (newRsETHPrice > highestRsethPrice) {
if (newRsETHPrice > highestRsethPrice) {
// check if the price is above the threshold
// check if the price is above the threshold
uint256 priceDifference = newRsETHPrice - highestRsethPrice;
uint256 priceDifference = newRsETHPrice - highestRsethPrice;
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
// pricePercentageLimit is in 1e18 precision (100% = 1e18, 1% = 1e16)
bool isPriceIncreaseOffLimit =
bool isPriceIncreaseOffLimit =
कॉपी
कॉपी हुआ
कॉपी
कॉपी हुआ
pricePercentageLimit > 0 && priceDifference >
(
pricePercentageLimit
*
highestRsethPrice)
/ 1e18
;
pricePercentageLimit > 0 && priceDifference >
pricePercentageLimit
.mulWad(
highestRsethPrice)
;
// check if the price difference is above the threshold
// check if the price difference is above the threshold
if (isPriceIncreaseOffLimit) {
if (isPriceIncreaseOffLimit) {
// if sender has a manager role, this doesn't revert.
// if sender has a manager role, this doesn't revert.
सेव किए गए Diffs
ऑरिजनल टेक्स्ट
फ़ाइल खोलें
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.27; import { UtilLib } from "./utils/UtilLib.sol"; import { LRTConstants } from "./utils/LRTConstants.sol"; import { LRTConfigRoleChecker, ILRTConfig } from "./utils/LRTConfigRoleChecker.sol"; import { IRSETH } from "./interfaces/IRSETH.sol"; import { IPriceFetcher } from "./interfaces/IPriceFetcher.sol"; import { ILRTOracle } from "./interfaces/ILRTOracle.sol"; import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; interface IPausable { function pause() external; } /// @title LRTOracle Contract /// @notice oracle contract that calculates the exchange rate of assets contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, Initializable { mapping(address asset => address priceOracle) public override assetPriceOracle; uint256 public override rsETHPrice; uint256 public pricePercentageLimit; uint256 public highestRsethPrice; // legacy variables uint256 public legacy_cooldownPeriodInTimestamp; uint256 public legacy_lastUpdatedCoolDownTimestamp; modifier onlySupportedOracle(address asset) { if (assetPriceOracle[asset] == address(0)) { revert AssetOracleNotSupported(); } _; } /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// @dev Initializes the contract /// @param lrtConfigAddr LRT config address function initialize(address lrtConfigAddr) external initializer { UtilLib.checkNonZeroAddress(lrtConfigAddr); lrtConfig = ILRTConfig(lrtConfigAddr); emit UpdatedLRTConfig(lrtConfigAddr); } /*////////////////////////////////////////////////////////////// write functions //////////////////////////////////////////////////////////////*/ /// @notice updates RSETH/ETH exchange rate /// @dev calculates based on stakedAsset value received from eigen layer function updateRSETHPrice() public { address rsETHTokenAddress = lrtConfig.rsETH(); uint256 rsethSupply = IRSETH(rsETHTokenAddress).totalSupply(); if (rsethSupply == 0) { rsETHPrice = 1 ether; highestRsethPrice = 1 ether; return; } if (highestRsethPrice == 0) { highestRsethPrice = rsETHPrice; } uint256 previousPrice = rsETHPrice; // get total ETH in the protocol uint256 totalETHInProtocol = _getTotalEthInProtocol(); // calculate previousTVL using rsethSupply multiplied by rsETHPrice uint256 previousTVL = rsethSupply * rsETHPrice; // only take fee if TVL increased uint256 protocolFeeInETH = 0; if (totalETHInProtocol > previousTVL) { uint256 rewardAmount = totalETHInProtocol - previousTVL; protocolFeeInETH = (rewardAmount * lrtConfig.protocolFeeInBPS()) / 10_000; } // compute new rsETH price based on total ETH minus fee uint256 newRsETHPrice = (totalETHInProtocol - protocolFeeInETH) / rsethSupply; if (newRsETHPrice > highestRsethPrice) { // check if the price is above the threshold uint256 priceDifference = newRsETHPrice - highestRsethPrice; bool isPriceIncreaseOffLimit = pricePercentageLimit > 0 && priceDifference > (pricePercentageLimit * highestRsethPrice) / 1e18; // check if the price difference is above the threshold if (isPriceIncreaseOffLimit) { // if sender has a manager role, this doesn't revert. // if not, it reverts as price went above the threshold if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.MANAGER, msg.sender)) { revert PriceAboveDailyThreshold(); } } } // downside protection — pause if price drops too far if (newRsETHPrice < highestRsethPrice) { uint256 diff = highestRsethPrice - newRsETHPrice; bool isPriceDecreaseOffLimit = pricePercentageLimit > 0 && diff > (pricePercentageLimit * highestRsethPrice) / 1e18; emit RsETHPriceDecrease(highestRsethPrice, newRsETHPrice); if (isPriceDecreaseOffLimit) { IPausable lrtDepositPool = IPausable(lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL)); IPausable withdrawalManager = IPausable(lrtConfig.getContract(LRTConstants.LRT_WITHDRAW_MANAGER)); lrtDepositPool.pause(); withdrawalManager.pause(); return; } } // update highest price if new price exceeds it if (newRsETHPrice > highestRsethPrice) { highestRsethPrice = newRsETHPrice; } // mint protocol fee as rsETH if there's a fee to take if (protocolFeeInETH > 0) { uint256 rsethAmountToMintAsProtocolFee = protocolFeeInETH / newRsETHPrice; if (rsethAmountToMintAsProtocolFee > 0) { address treasury = lrtConfig.getContract(LRTConstants.PROTOCOL_TREASURY); IRSETH(rsETHTokenAddress).mint(treasury, rsethAmountToMintAsProtocolFee); emit FeeMinted(treasury, rsethAmountToMintAsProtocolFee); } } rsETHPrice = newRsETHPrice; emit RsETHPriceUpdate(rsETHPrice, previousPrice); } /// @dev update rseth price as an manager account /// @dev main benefit is to be able to update the price in case of the price going above the threshold /// @dev only onlyLRTManager is allowed function updateRSETHPriceAsManager() external onlyLRTManager { updateRSETHPrice(); } /// @dev add/update the price oracle of any asset /// @dev only onlyLRTAdmin is allowed /// @param asset asset address for which oracle price needs to be added/updated function updatePriceOracleForValidated(address asset, address priceOracle) external onlyLRTAdmin { //sanity check that oracle has 1e18 precision uint256 price = IPriceFetcher(priceOracle).getAssetPrice(asset); if (price > 1e19 || price < 1e18) { revert InvalidPriceOracle(); } updatePriceOracleFor(asset, priceOracle); } /// @dev add/update the price oracle of any asset /// @dev only onlyLRTAdmin is allowed /// @param asset asset address for which oracle price needs to be added/updated function updatePriceOracleFor(address asset, address priceOracle) public onlyLRTAdmin { UtilLib.checkNonZeroAddress(priceOracle); assetPriceOracle[asset] = priceOracle; emit AssetPriceOracleUpdate(asset, priceOracle); } /// @dev set the price percentage limit. Only onlyLRTAdmin is allowed /// @dev PricePercentageLimit for 1% is 1e16 /// @dev Price Percentage Limit for 100% is 1e18 /// @param _pricePercentageLimit price percentage limit function setPricePercentageLimit(uint256 _pricePercentageLimit) external onlyLRTAdmin { pricePercentageLimit = _pricePercentageLimit; emit PricePercentageLimitUpdate(_pricePercentageLimit); } /*////////////////////////////////////////////////////////////// view functions //////////////////////////////////////////////////////////////*/ /// @notice Provides Asset/ETH exchange rate /// @dev reads from priceFetcher interface which may fetch price from any supported oracle /// @param asset the asset for which exchange rate is required /// @return assetPrice exchange rate of asset function getAssetPrice(address asset) public view onlySupportedOracle(asset) returns (uint256) { return IPriceFetcher(assetPriceOracle[asset]).getAssetPrice(asset); } /*////////////////////////////////////////////////////////////// private functions //////////////////////////////////////////////////////////////*/ /// @notice get total ETH in protocol /// @return totalETHInProtocol total ETH in protocol function _getTotalEthInProtocol() private view returns (uint256 totalETHInProtocol) { address lrtDepositPoolAddr = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); address[] memory supportedAssets = lrtConfig.getSupportedAssetList(); uint256 supportedAssetCount = supportedAssets.length; for (uint16 assetIdx; assetIdx < supportedAssetCount;) { address asset = supportedAssets[assetIdx]; uint256 assetER = getAssetPrice(asset); uint256 totalAssetAmt = ILRTDepositPool(lrtDepositPoolAddr).getTotalAssetDeposits(asset); totalETHInProtocol += totalAssetAmt * assetER; unchecked { ++assetIdx; } } } }
परिवर्तित टेक्स्ट
फ़ाइल खोलें
// SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.27; import { UtilLib } from "./utils/UtilLib.sol"; import { LRTConstants } from "./utils/LRTConstants.sol"; import { LRTConfigRoleChecker, ILRTConfig } from "./utils/LRTConfigRoleChecker.sol"; import { WadMath } from "./utils/WadMath.sol"; import { IRSETH } from "./interfaces/IRSETH.sol"; import { IPriceFetcher } from "./interfaces/IPriceFetcher.sol"; import { ILRTOracle } from "./interfaces/ILRTOracle.sol"; import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; import { IAccessControl } from "@openzeppelin/contracts/access/IAccessControl.sol"; import { Initializable } from "@openzeppelin/contracts-upgradeable/proxy/utils/Initializable.sol"; interface IPausable { function pause() external; function paused() external view returns (bool); } /// @title LRTOracle Contract /// @notice oracle contract that calculates the exchange rate of assets contract LRTOracle is ILRTOracle, LRTConfigRoleChecker, Initializable { using WadMath for uint256; mapping(address asset => address priceOracle) public override assetPriceOracle; uint256 public override rsETHPrice; uint256 public pricePercentageLimit; uint256 public highestRsethPrice; // Daily fee minting limit variables uint256 public currentPeriodMintedFeeAmount; uint256 public feePeriodStartTime; uint256 public maxFeeMintAmountPerDay; /// @notice New variable added for pausable functionality bool public paused; modifier onlySupportedOracle(address asset) { if (assetPriceOracle[asset] == address(0)) { revert AssetOracleNotSupported(); } _; } modifier whenNotPaused() { if (paused) revert ContractPaused(); _; } modifier whenPaused() { if (!paused) revert ContractNotPaused(); _; } /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); } /// @dev Initializes the contract /// @param lrtConfigAddr LRT config address function initialize(address lrtConfigAddr) external initializer { UtilLib.checkNonZeroAddress(lrtConfigAddr); lrtConfig = ILRTConfig(lrtConfigAddr); emit UpdatedLRTConfig(lrtConfigAddr); } /*////////////////////////////////////////////////////////////// write functions //////////////////////////////////////////////////////////////*/ /// @notice updates RSETH/ETH exchange rate /// @dev calculates rsETH price based on stakedAsset value received from EigenLayer function updateRSETHPrice() public whenNotPaused { _updateRsETHPrice(); } /// @dev update rsETH price as an manager account /// @dev main benefit is to be able to update the price in case of the price going above the threshold /// @dev only LRT manager is allowed to call this function function updateRSETHPriceAsManager() external onlyLRTManager { _updateRsETHPrice(); } /// @dev add/update the price oracle of any asset /// @dev only onlyLRTAdmin is allowed /// @param asset asset address for which oracle price needs to be added/updated function updatePriceOracleForValidated(address asset, address priceOracle) external onlyLRTAdmin { // Sanity check: oracle price must have precision between 1e16 and 1e19 uint256 price = IPriceFetcher(priceOracle).getAssetPrice(asset); if (price > 1e19 || price < 1e16) { revert InvalidPriceOracle(); } updatePriceOracleFor(asset, priceOracle); } /// @dev add/update the price oracle of any asset /// @dev only onlyLRTAdmin is allowed /// @param asset asset address for which oracle price needs to be added/updated function updatePriceOracleFor(address asset, address priceOracle) public onlyLRTAdmin { if (lrtConfig.isSupportedAsset(asset)) { UtilLib.checkNonZeroAddress(priceOracle); } assetPriceOracle[asset] = priceOracle; emit AssetPriceOracleUpdate(asset, priceOracle); } /// @dev set the price percentage limit. Only onlyLRTAdmin is allowed /// @dev PricePercentageLimit for 1% is 1e16 /// @dev Price Percentage Limit for 100% is 1e18 /// @param _pricePercentageLimit price percentage limit function setPricePercentageLimit(uint256 _pricePercentageLimit) external onlyLRTAdmin { pricePercentageLimit = _pricePercentageLimit; emit PricePercentageLimitUpdate(_pricePercentageLimit); } /// @dev set the maximum fee minting amount per day. Only onlyLRTManager is allowed /// @param _maxFeeMintAmountPerDay maximum amount of fee that can be minted per day function setMaxFeeMintAmountPerDay(uint256 _maxFeeMintAmountPerDay) external onlyLRTManager { maxFeeMintAmountPerDay = _maxFeeMintAmountPerDay; emit MaxFeeMintAmountPerDayUpdated(_maxFeeMintAmountPerDay); } /// @dev Pauses the pausable methods in the contract function pause() external onlyLRTManager whenNotPaused { _pause(); } /// @dev Unpauses the pausable methods in the contract function unpause() external onlyLRTAdmin whenPaused { paused = false; emit Unpaused(msg.sender); } /*////////////////////////////////////////////////////////////// view functions //////////////////////////////////////////////////////////////*/ /// @notice Provides Asset/ETH exchange rate /// @dev reads from priceFetcher interface which may fetch price from any supported oracle /// @param asset the asset for which exchange rate is required /// @return assetPrice exchange rate of asset function getAssetPrice(address asset) public view onlySupportedOracle(asset) returns (uint256) { return IPriceFetcher(assetPriceOracle[asset]).getAssetPrice(asset); } /*////////////////////////////////////////////////////////////// internal functions //////////////////////////////////////////////////////////////*/ /// @dev Checks and updates daily fee minting limits /// @param feeAmount The amount of fee to be minted function _checkAndUpdateDailyFeeMintLimit(uint256 feeAmount) internal { // Reset or initialize the period if it's unset or a day has passed if (feePeriodStartTime == 0 || block.timestamp >= feePeriodStartTime + 1 days) { currentPeriodMintedFeeAmount = 0; feePeriodStartTime = block.timestamp; } // Check if minting would exceed the daily limit if (currentPeriodMintedFeeAmount + feeAmount > maxFeeMintAmountPerDay) { revert DailyFeeMintLimitExceeded(currentPeriodMintedFeeAmount + feeAmount, maxFeeMintAmountPerDay); } currentPeriodMintedFeeAmount += feeAmount; } /// @dev Internal function to update rsETH price // solhint-disable-next-line code-complexity function _updateRsETHPrice() internal { address rsETHTokenAddress = lrtConfig.rsETH(); uint256 rsethSupply = IRSETH(rsETHTokenAddress).totalSupply(); if (rsethSupply == 0) { rsETHPrice = 1 ether; highestRsethPrice = 1 ether; return; } if (highestRsethPrice == 0) { highestRsethPrice = rsETHPrice; } uint256 previousPrice = rsETHPrice; // get total ETH in the protocol (normalized to 1e18) uint256 totalETHInProtocol = _getTotalEthInProtocol(); // calculate previousTVL using rsethSupply multiplied by rsETHPrice uint256 previousTVL = rsethSupply.mulWad(rsETHPrice); IPausable lrtDepositPool = IPausable(lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL)); IPausable withdrawalManager = IPausable(lrtConfig.getContract(LRTConstants.LRT_WITHDRAW_MANAGER)); // determine if the protocol is active (not paused) bool protocolPaused = lrtDepositPool.paused() || withdrawalManager.paused() || paused; // only take fee if TVL increased and protocol is not paused uint256 protocolFeeInETH = 0; if (!protocolPaused && totalETHInProtocol > previousTVL) { uint256 rewardAmount = totalETHInProtocol - previousTVL; protocolFeeInETH = (rewardAmount * lrtConfig.protocolFeeInBPS()) / 10_000; } // compute new rsETH price based on total ETH minus fee uint256 newRsETHPrice = (totalETHInProtocol - protocolFeeInETH).divWad(rsethSupply); if (newRsETHPrice > highestRsethPrice) { // check if the price is above the threshold uint256 priceDifference = newRsETHPrice - highestRsethPrice; // pricePercentageLimit is in 1e18 precision (100% = 1e18, 1% = 1e16) bool isPriceIncreaseOffLimit = pricePercentageLimit > 0 && priceDifference > pricePercentageLimit.mulWad(highestRsethPrice); // check if the price difference is above the threshold if (isPriceIncreaseOffLimit) { // if sender has a manager role, this doesn't revert. // if not, it reverts as price went above the threshold if (!IAccessControl(address(lrtConfig)).hasRole(LRTConstants.MANAGER, msg.sender)) { revert PriceAboveDailyThreshold(); } } } // downside protection — pause if price drops too far if (newRsETHPrice < highestRsethPrice) { uint256 diff = highestRsethPrice - newRsETHPrice; // normalizing to 1e18 bool isPriceDecreaseOffLimit = pricePercentageLimit > 0 && diff > pricePercentageLimit.mulWad(highestRsethPrice); // if price decrease is off limit, pause the protocol (unless it's already paused) if (isPriceDecreaseOffLimit) { if (!lrtDepositPool.paused()) lrtDepositPool.pause(); if (!withdrawalManager.paused()) withdrawalManager.pause(); _pause(); return; } // if price has decreased compared to the previous price, emit an event to reflect that if (previousPrice > newRsETHPrice) { emit RsETHPriceDecrease(newRsETHPrice, previousPrice); } // emit an event to notify that the price is currently below the peak (all time high) price emit RsETHPriceBelowPeak(highestRsethPrice, newRsETHPrice); } // update highest price if new price exceeds it if (newRsETHPrice > highestRsethPrice) { highestRsethPrice = newRsETHPrice; } // mint protocol fee as rsETH if there's a fee to take if (protocolFeeInETH > 0) { // Calculate rsETH amount to mint as protocol fee uint256 rsethAmountToMintAsProtocolFee = protocolFeeInETH.divWad(newRsETHPrice); // Calculate TVL increase in rsETH uint256 tvlIncreaseInRsETH = (totalETHInProtocol - previousTVL).divWad(newRsETHPrice); // invariant ensures protocol fee doesn't exceed TVL increase // this prevents taking more fees than the actual gains in the protocol if (rsethAmountToMintAsProtocolFee > tvlIncreaseInRsETH) { revert ProtocolFeeExceededTVLIncrease(); } _checkAndUpdateDailyFeeMintLimit(rsethAmountToMintAsProtocolFee); if (rsethAmountToMintAsProtocolFee > 0) { address treasury = lrtConfig.getContract(LRTConstants.PROTOCOL_TREASURY); IRSETH(rsETHTokenAddress).mint(treasury, rsethAmountToMintAsProtocolFee); emit FeeMinted(treasury, rsethAmountToMintAsProtocolFee); } } else { _checkAndUpdateDailyFeeMintLimit(0); } rsETHPrice = newRsETHPrice; emit RsETHPriceUpdate(rsETHPrice, previousPrice); } /// @dev Internal function to pause the contract function _pause() internal { if (paused) return; paused = true; emit Paused(msg.sender); } /*////////////////////////////////////////////////////////////// private functions //////////////////////////////////////////////////////////////*/ /// @notice get total ETH in protocol /// @return totalETHInProtocol total ETH in protocol (normalized to 1e18) function _getTotalEthInProtocol() private view returns (uint256 totalETHInProtocol) { address lrtDepositPoolAddr = lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL); address[] memory supportedAssets = lrtConfig.getSupportedAssetList(); uint256 supportedAssetCount = supportedAssets.length; for (uint16 assetIdx; assetIdx < supportedAssetCount;) { address asset = supportedAssets[assetIdx]; // assetER is in 1e18 precision (1.0 = 1e18) uint256 assetER = getAssetPrice(asset); // totalAssetAmt is in 1e18 precision (standard token decimals) uint256 totalAssetAmt = ILRTDepositPool(lrtDepositPoolAddr).getTotalAssetDeposits(asset); totalETHInProtocol += totalAssetAmt.mulWad(assetER); unchecked { ++assetIdx; } } } }
अंतर खोजें