Diff
checker
Texte
Texte
Images
Documents
Excel
Dossiers
Legal
Enterprise
Application de bureau
Prix
Se connecter
Télécharger Diffchecker Desktop
Comparer le texte
Trouver la différence entre deux fichiers texte
Outils
Historique
Affichage
Vue
Divisé
Unifié
Éditeur live
Masquer les espaces
Cacher identiques
Sans retour à la ligne
Niveau de précision
Intelligent
Syntaxe
Aucun
Modifier l’apparence
Traitement
Ignorer
Transformer le texte
Aller au premier écart
Modifier l'entrée
Diffchecker Desktop
La façon la plus sécurisée d'utiliser Diffchecker. Obtenez l'application Diffchecker Desktop : vos diffs ne quittent jamais votre ordinateur !
Obtenir Desktop
LRTDepositPool
Créé
il y a 12 mois
Le diff n'expire jamais
Effacer
Exporter
Partager
Expliquer
34 suppressions
Lignes
Total
Supprimé
Caractères
Total
Supprimé
Pour continuer à utiliser cette fonctionnalité, passez à
Diff
checker
Pro
Voir les prix
622 lignes
Copier tout
45 ajouts
Lignes
Total
Ajouté
Caractères
Total
Ajouté
Pour continuer à utiliser cette fonctionnalité, passez à
Diff
checker
Pro
Voir les prix
625 lignes
Copier tout
// 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 { IRSETH } from "./interfaces/IRSETH.sol";
import { IRSETH } from "./interfaces/IRSETH.sol";
import { ILRTOracle } from "./interfaces/ILRTOracle.sol";
import { ILRTOracle } from "./interfaces/ILRTOracle.sol";
import { INodeDelegator } from "./interfaces/INodeDelegator.sol";
import { INodeDelegator } from "./interfaces/INodeDelegator.sol";
import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol";
import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol";
import { ILRTUnstakingVault } from "./interfaces/ILRTUnstakingVault.sol";
import { ILRTUnstakingVault } from "./interfaces/ILRTUnstakingVault.sol";
import { ILRTConverter } from "./interfaces/ILRTConverter.sol";
import { ILRTConverter } from "./interfaces/ILRTConverter.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol";
Copier
Copié
Copier
Copié
import {
ReentrancyGuardUpgradeable
} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import {
ReentrancyGuardUpgradeable
} from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import { ILido } from "./external/lido/ILido.sol";
import { ILido } from "./external/lido/ILido.sol";
/// @title LRTDepositPool - Deposit Pool Contract for LSTs
/// @title LRTDepositPool - Deposit Pool Contract for LSTs
/// @notice Handles LST asset deposits
/// @notice Handles LST asset deposits
contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {
contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable {
using SafeERC20 for IERC20;
using SafeERC20 for IERC20;
uint256 public maxNodeDelegatorLimit;
uint256 public maxNodeDelegatorLimit;
uint256 public minAmountToDeposit;
uint256 public minAmountToDeposit;
mapping(address => uint256) public isNodeDelegator; // 0: not a node delegator, 1: is a node delegator
mapping(address => uint256) public isNodeDelegator; // 0: not a node delegator, 1: is a node delegator
address[] public nodeDelegatorQueue;
address[] public nodeDelegatorQueue;
/// @notice maximum amount that can be ignored
/// @notice maximum amount that can be ignored
uint256 public maxNegligibleAmount;
uint256 public maxNegligibleAmount;
/// @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);
__Pausable_init();
__Pausable_init();
__ReentrancyGuard_init();
__ReentrancyGuard_init();
maxNodeDelegatorLimit = 10;
maxNodeDelegatorLimit = 10;
lrtConfig = ILRTConfig(lrtConfigAddr);
lrtConfig = ILRTConfig(lrtConfigAddr);
emit UpdatedLRTConfig(lrtConfigAddr);
emit UpdatedLRTConfig(lrtConfigAddr);
}
}
/*//////////////////////////////////////////////////////////////
/*//////////////////////////////////////////////////////////////
receive functions
receive functions
//////////////////////////////////////////////////////////////*/
//////////////////////////////////////////////////////////////*/
receive() external payable { }
receive() external payable { }
/// @dev receive from RewardReceiver
/// @dev receive from RewardReceiver
function receiveFromRewardReceiver() external payable { }
function receiveFromRewardReceiver() external payable { }
/// @dev receive from LRTConverter
/// @dev receive from LRTConverter
function receiveFromLRTConverter() external payable { }
function receiveFromLRTConverter() external payable { }
/// @dev receive from NodeDelegator
/// @dev receive from NodeDelegator
function receiveFromNodeDelegator() external payable { }
function receiveFromNodeDelegator() external payable { }
/*//////////////////////////////////////////////////////////////
/*//////////////////////////////////////////////////////////////
user interactions
user interactions
//////////////////////////////////////////////////////////////*/
//////////////////////////////////////////////////////////////*/
/// @notice Allows user to deposit ETH to the protocol
/// @notice Allows user to deposit ETH to the protocol
/// @param minRSETHAmountExpected Minimum amount of rseth to receive
/// @param minRSETHAmountExpected Minimum amount of rseth to receive
/// @param referralId referral id
/// @param referralId referral id
function depositETH(
function depositETH(
uint256 minRSETHAmountExpected,
uint256 minRSETHAmountExpected,
string calldata referralId
string calldata referralId
)
)
external
external
payable
payable
nonReentrant
nonReentrant
whenNotPaused
whenNotPaused
Copier
Copié
Copier
Copié
onlySupportedAsset(LRTConstants.ETH_TOKEN)
{
{
// checks
// checks
uint256 rsethAmountToMint = _beforeDeposit(LRTConstants.ETH_TOKEN, msg.value, minRSETHAmountExpected);
uint256 rsethAmountToMint = _beforeDeposit(LRTConstants.ETH_TOKEN, msg.value, minRSETHAmountExpected);
// interactions
// interactions
_mintRsETH(rsethAmountToMint);
_mintRsETH(rsethAmountToMint);
emit ETHDeposit(msg.sender, msg.value, rsethAmountToMint, referralId);
emit ETHDeposit(msg.sender, msg.value, rsethAmountToMint, referralId);
}
}
/// @notice helps user stake LST to the protocol
/// @notice helps user stake LST to the protocol
/// @param asset LST asset address to stake
/// @param asset LST asset address to stake
/// @param depositAmount LST asset amount to stake
/// @param depositAmount LST asset amount to stake
/// @param minRSETHAmountExpected Minimum amount of rseth to receive
/// @param minRSETHAmountExpected Minimum amount of rseth to receive
function depositAsset(
function depositAsset(
address asset,
address asset,
uint256 depositAmount,
uint256 depositAmount,
uint256 minRSETHAmountExpected,
uint256 minRSETHAmountExpected,
Différences enregistrées
Texte d'origine
Ouvrir un fichier
// 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 { ILRTOracle } from "./interfaces/ILRTOracle.sol"; import { INodeDelegator } from "./interfaces/INodeDelegator.sol"; import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; import { ILRTUnstakingVault } from "./interfaces/ILRTUnstakingVault.sol"; import { ILRTConverter } from "./interfaces/ILRTConverter.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ILido } from "./external/lido/ILido.sol"; /// @title LRTDepositPool - Deposit Pool Contract for LSTs /// @notice Handles LST asset deposits contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable { using SafeERC20 for IERC20; uint256 public maxNodeDelegatorLimit; uint256 public minAmountToDeposit; mapping(address => uint256) public isNodeDelegator; // 0: not a node delegator, 1: is a node delegator address[] public nodeDelegatorQueue; /// @notice maximum amount that can be ignored uint256 public maxNegligibleAmount; /// @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); __Pausable_init(); __ReentrancyGuard_init(); maxNodeDelegatorLimit = 10; lrtConfig = ILRTConfig(lrtConfigAddr); emit UpdatedLRTConfig(lrtConfigAddr); } /*////////////////////////////////////////////////////////////// receive functions //////////////////////////////////////////////////////////////*/ receive() external payable { } /// @dev receive from RewardReceiver function receiveFromRewardReceiver() external payable { } /// @dev receive from LRTConverter function receiveFromLRTConverter() external payable { } /// @dev receive from NodeDelegator function receiveFromNodeDelegator() external payable { } /*////////////////////////////////////////////////////////////// user interactions //////////////////////////////////////////////////////////////*/ /// @notice Allows user to deposit ETH to the protocol /// @param minRSETHAmountExpected Minimum amount of rseth to receive /// @param referralId referral id function depositETH( uint256 minRSETHAmountExpected, string calldata referralId ) external payable nonReentrant whenNotPaused { // checks uint256 rsethAmountToMint = _beforeDeposit(LRTConstants.ETH_TOKEN, msg.value, minRSETHAmountExpected); // interactions _mintRsETH(rsethAmountToMint); emit ETHDeposit(msg.sender, msg.value, rsethAmountToMint, referralId); } /// @notice helps user stake LST to the protocol /// @param asset LST asset address to stake /// @param depositAmount LST asset amount to stake /// @param minRSETHAmountExpected Minimum amount of rseth to receive function depositAsset( address asset, uint256 depositAmount, uint256 minRSETHAmountExpected, string calldata referralId ) external nonReentrant whenNotPaused onlySupportedERC20Token(asset) { // checks uint256 rsethAmountToMint = _beforeDeposit(asset, depositAmount, minRSETHAmountExpected); // interactions IERC20(asset).safeTransferFrom(msg.sender, address(this), depositAmount); _mintRsETH(rsethAmountToMint); emit AssetDeposit(msg.sender, asset, depositAmount, rsethAmountToMint, referralId); } /*////////////////////////////////////////////////////////////// Fund movement functions //////////////////////////////////////////////////////////////*/ /// @notice swap ETH for LST asset which is accepted by LRTDepositPool /// @dev use LRTOracle to get price for toToken. Only callable by LRT manager /// @param toAsset Asset address to swap to /// @param minToAssetAmount Minimum asset amount to swap to function swapETHForAssetWithinDepositPool( address toAsset, uint256 minToAssetAmount ) external payable nonReentrant onlyLRTManager onlySupportedERC20Token(toAsset) { // checks uint256 ethAmountSent = msg.value; if (ethAmountSent == 0) { revert ZeroAssetAmount(); } uint256 returnAmount = getSwapETHToAssetReturnAmount(toAsset, ethAmountSent); if (minToAssetAmount > returnAmount) { revert MinAssetAmountNotMet(); } if (IERC20(toAsset).balanceOf(address(this)) < returnAmount) { revert NotEnoughAssetToTransfer(); } // interactions IERC20(toAsset).safeTransfer(msg.sender, returnAmount); emit ETHSwappedForLST(ethAmountSent, toAsset, returnAmount); } /// @notice swap LST Asset for ETH which is accepted by LRTDepositPool /// @dev use LRTOracle to get price for fromAsset. Only callable by LRT operator /// @param fromAsset Asset address to swap from /// @param fromAssetAmount Asset amount to swap from /// @param minETHAmountExpected Minimum ETH amount to swap to function swapAssetForETHWithinDepositPool( address fromAsset, uint256 fromAssetAmount, uint256 minETHAmountExpected ) external nonReentrant onlyLRTOperator onlySupportedERC20Token(fromAsset) { if (fromAssetAmount == 0) { revert ZeroAssetAmount(); } // checks uint256 returnAmount = getSwapAssetForETHReturnAmount(fromAsset, fromAssetAmount); if (minETHAmountExpected > returnAmount) { revert MinAssetAmountNotMet(); } if (address(this).balance < returnAmount) { revert NotEnoughETHToTransfer(); } IERC20(fromAsset).safeTransferFrom(msg.sender, address(this), fromAssetAmount); (bool success,) = payable(msg.sender).call{ value: returnAmount }(""); if (!success) revert EthTransferFailed(); emit AssetSwappedForETH(fromAsset, fromAssetAmount, returnAmount); } /// @notice transfers asset lying in this DepositPool to node delegator contract /// @dev only callable by LRT Operator /// @param ndcIndex Index of NodeDelegator contract address in nodeDelegatorQueue /// @param asset Asset address /// @param amount Asset amount to transfer function transferAssetToNodeDelegator( uint256 ndcIndex, address asset, uint256 amount ) external nonReentrant onlyLRTOperator onlySupportedERC20Token(asset) { address nodeDelegator = nodeDelegatorQueue[ndcIndex]; IERC20(asset).safeTransfer(nodeDelegator, amount); } /// @notice transfers ETH lying in this DepositPool to node delegator contract /// @dev only callable by LRT Operator /// @param ndcIndex Index of NodeDelegator contract address in nodeDelegatorQueue /// @param amount ETH amount to transfer function transferETHToNodeDelegator(uint256 ndcIndex, uint256 amount) external nonReentrant onlyLRTOperator { address nodeDelegator = nodeDelegatorQueue[ndcIndex]; INodeDelegator(nodeDelegator).sendETHFromDepositPoolToNDC{ value: amount }(); emit EthTransferred(nodeDelegator, amount); } /// @notice transfers asset lying in this DepositPool to LRTUnstakingVault contract /// @dev only callable by LRT Operator /// @param asset Asset address /// @param amount Asset amount to transfer function transferAssetToLRTUnstakingVault( address asset, uint256 amount ) external nonReentrant onlyLRTOperator onlySupportedERC20Token(asset) { address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); IERC20(asset).safeTransfer(lrtUnstakingVault, amount); } /// @notice transfers ETH lying in this DepositPool to nLRTUnstakingVault contract /// @dev only callable by LRT Operator /// @param amount ETH amount to transfer function transferETHToLRTUnstakingVault(uint256 amount) external nonReentrant onlyLRTOperator { address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); ILRTUnstakingVault(lrtUnstakingVault).receiveFromLRTDepositPool{ value: amount }(); emit EthTransferred(lrtUnstakingVault, amount); } /*////////////////////////////////////////////////////////////// Setters / Update Functions //////////////////////////////////////////////////////////////*/ /// @notice maximum amount that can be ignored /// @dev only callable by LRT admin /// @param maxNegligibleAmount_ Maximum amount that can be ignored function setMaxNegligibleAmount(uint256 maxNegligibleAmount_) external onlyLRTAdmin { maxNegligibleAmount = maxNegligibleAmount_; emit MaxNegligibleAmountUpdated(maxNegligibleAmount_); } /// @notice update min amount to deposit /// @dev only callable by LRT admin /// @param minAmountToDeposit_ Minimum amount to deposit function setMinAmountToDeposit(uint256 minAmountToDeposit_) external onlyLRTAdmin { minAmountToDeposit = minAmountToDeposit_; emit MinAmountToDepositUpdated(minAmountToDeposit_); } /// @notice update max node delegator count /// @dev only callable by LRT admin /// @param maxNodeDelegatorLimit_ Maximum count of node delegator function updateMaxNodeDelegatorLimit(uint256 maxNodeDelegatorLimit_) external onlyLRTAdmin { if (maxNodeDelegatorLimit_ < nodeDelegatorQueue.length) { revert InvalidMaximumNodeDelegatorLimit(); } maxNodeDelegatorLimit = maxNodeDelegatorLimit_; emit MaxNodeDelegatorLimitUpdated(maxNodeDelegatorLimit); } /// @notice add new node delegator contract addresses /// @dev only callable by LRT admin /// @param nodeDelegatorContracts Array of NodeDelegator contract addresses function addNodeDelegatorContractToQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin { uint256 length = nodeDelegatorContracts.length; if (nodeDelegatorQueue.length + length > maxNodeDelegatorLimit) { revert MaximumNodeDelegatorLimitReached(); } for (uint256 i; i < length;) { UtilLib.checkNonZeroAddress(nodeDelegatorContracts[i]); // check if node delegator contract is already added and add it if not if (isNodeDelegator[nodeDelegatorContracts[i]] == 0) { nodeDelegatorQueue.push(nodeDelegatorContracts[i]); } isNodeDelegator[nodeDelegatorContracts[i]] = 1; unchecked { ++i; } } emit NodeDelegatorAddedinQueue(nodeDelegatorContracts); } /// @notice remove node delegator contract address from queue /// @dev only callable by LRT admin /// @param nodeDelegatorAddress NodeDelegator contract address function removeNodeDelegatorContractFromQueue(address nodeDelegatorAddress) external onlyLRTAdmin { _removeNodeDelegatorContractFromQueue(nodeDelegatorAddress); } /// @notice remove many node delegator contracts from queue /// @dev only callable by LRT admin /// @param nodeDelegatorContracts Array of NodeDelegator contract addresses function removeManyNodeDelegatorContractsFromQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin { uint256 length = nodeDelegatorContracts.length; for (uint256 i; i < length;) { _removeNodeDelegatorContractFromQueue(nodeDelegatorContracts[i]); unchecked { ++i; } } } /// @dev Triggers stopped state. Contract must not be paused. function pause() external onlyRole(LRTConstants.PAUSER_ROLE) { _pause(); } /// @dev Returns to normal state. Contract must be paused function unpause() external onlyLRTAdmin { _unpause(); } /*////////////////////////////////////////////////////////////// other write functions //////////////////////////////////////////////////////////////*/ /// @notice Approves the maximum amount of an asset to the LRTConverter contract /// @dev only supported assets can be deposited and only called by the LRT manager /// @param asset the asset to approve function maxApproveToLRTConverter(address asset) external onlySupportedERC20Token(asset) onlyLRTManager { address lrtConverterAddress = lrtConfig.getContract(LRTConstants.LRT_CONVERTER); IERC20(asset).forceApprove(lrtConverterAddress, type(uint256).max); } /*////////////////////////////////////////////////////////////// view functions //////////////////////////////////////////////////////////////*/ /// @notice gets the total asset present in protocol /// @param asset Asset address /// @return totalAssetDeposit total asset present in protocol function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) { ( uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer, uint256 assetUnstakingFromEigenLayer, uint256 assetLyingInConverter, uint256 assetLyingUnstakingVault ) = getAssetDistributionData(asset); uint256 effectiveAssetWithEigenLayer = assetStakedInEigenLayer + assetUnstakingFromEigenLayer; return ( assetLyingInDepositPool + assetLyingInNDCs + effectiveAssetWithEigenLayer + assetLyingInConverter + assetLyingUnstakingVault ); } /// @notice gets the current limit of asset deposit /// @param asset Asset address /// @return currentLimit Current limit of asset deposit function getAssetCurrentLimit(address asset) public view override returns (uint256) { uint256 totalAssetDeposits = getTotalAssetDeposits(asset); if (totalAssetDeposits > lrtConfig.depositLimitByAsset(asset)) { return 0; } return lrtConfig.depositLimitByAsset(asset) - totalAssetDeposits; } /// @dev get node delegator queue /// @return nodeDelegatorQueue Array of node delegator contract addresses function getNodeDelegatorQueue() external view override returns (address[] memory) { return nodeDelegatorQueue; } /// @dev provides asset amount distribution data among depositPool, NDCs and eigenLayer /// @param asset the asset to get the total amount of /// @return assetLyingInDepositPool asset amount lying in this LRTDepositPool contract /// @return assetLyingInNDCs asset amount sum lying in all NDC contract /// @return assetStakedInEigenLayer asset amount deposited in eigen layer strategies through all NDCs /// @return assetUnstakingFromEigenLayer asset amount in delayed withdrawal from eigen layer strategies through all /// NDCs /// @return assetLyingInConverter asset value lying in converter /// @return assetLyingUnstakingVault asset amount lying in UnstakingVault function getAssetDistributionData(address asset) public view override onlySupportedAsset(asset) returns ( uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer, uint256 assetUnstakingFromEigenLayer, uint256 assetLyingInConverter, uint256 assetLyingUnstakingVault ) { if (asset == LRTConstants.ETH_TOKEN) { return getETHDistributionData(); } assetLyingInDepositPool = IERC20(asset).balanceOf(address(this)); // NOTE: For legacy el withdrawal support, this can be removed after all pre slashing withdrawals are processed assetUnstakingFromEigenLayer = ILRTUnstakingVault(lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT)).getAssetsUnstaking(asset); uint256 ndcsCount = nodeDelegatorQueue.length; for (uint256 i; i < ndcsCount;) { assetLyingInNDCs += IERC20(asset).balanceOf(nodeDelegatorQueue[i]); assetStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetBalance(asset); assetUnstakingFromEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetUnstaking(asset); unchecked { ++i; } } address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); assetLyingInConverter = 0; //assets in converter are accounted in there eth value => getETHDistributionData assetLyingUnstakingVault = IERC20(asset).balanceOf(lrtUnstakingVault); } /// @dev provides ETH amount distribution data among depositPool, NDCs and eigenLayer /// @dev rewards are not accounted here /// it will automatically be accounted once it is moved from feeReceiver/rewardReceiver to depositPool function getETHDistributionData() public view override returns ( uint256 ethLyingInDepositPool, uint256 ethLyingInNDCs, uint256 ethStakedInEigenLayer, uint256 ethUnstakingFromEigenLayer, uint256 ethLyingInConverter, uint256 ethLyingInUnstakingVault ) { ethLyingInDepositPool = address(this).balance; uint256 ndcsCount = nodeDelegatorQueue.length; ethUnstakingFromEigenLayer = ILRTUnstakingVault(lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT)) .getAssetsUnstaking(LRTConstants.ETH_TOKEN); for (uint256 i; i < ndcsCount;) { ethLyingInNDCs += nodeDelegatorQueue[i].balance; ethStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getEffectivePodShares(); ethUnstakingFromEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetUnstaking(LRTConstants.ETH_TOKEN); unchecked { ++i; } } address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); ethLyingInUnstakingVault = lrtUnstakingVault.balance; address lrtConverter = lrtConfig.getContract(LRTConstants.LRT_CONVERTER); ethLyingInConverter = ILRTConverter(lrtConverter).ethValueInWithdrawal(); } /// @notice View amount of rsETH to mint for given asset amount /// @param asset Asset address /// @param amount Asset amount /// @return rsethAmountToMint Amount of rseth to mint function getRsETHAmountToMint( address asset, uint256 amount ) public view override returns (uint256 rsethAmountToMint) { // setup oracle contract address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); // calculate rseth amount to mint based on asset amount and asset exchange rate rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.rsETHPrice(); } /// @notice get return amount for swapping ETH to asset that is accepted by LRTDepositPool /// @dev use LRTOracle to get price for toToken /// @param toAsset Asset address to swap to /// @param ethAmountToSend Eth amount to swap from /// @return returnAmount Return amount of toAsset function getSwapETHToAssetReturnAmount( address toAsset, uint256 ethAmountToSend ) public view returns (uint256 returnAmount) { address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); uint256 ethPricePerUint = 1e18; return ethPricePerUint * ethAmountToSend / lrtOracle.getAssetPrice(toAsset); } /// @notice get return amount for swapping asset to ETH that is accepted by LRTDepositPool /// @dev use LRTOracle to get price for fromAsset /// @param fromAsset Asset address to swap from /// @param fromAssetAmount Asset amount to swap from /// @return returnAmount Return amount of ETH function getSwapAssetForETHReturnAmount( address fromAsset, uint256 fromAssetAmount ) public view returns (uint256 returnAmount) { address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); return lrtOracle.getAssetPrice(fromAsset) * fromAssetAmount / 1e18; } /// @notice Stakes ETH with Lido to receive stETH /// @param referral Optional referral address for Lido function stakeEthForStETH(address referral, uint256 ethAmount) external onlyLRTManager { address stETHAddress = lrtConfig.getLSTToken(LRTConstants.ST_ETH_TOKEN); uint256 stETHShares = ILido(stETHAddress).submit{ value: ethAmount }(referral); emit AssetStaked(stETHAddress, ethAmount, stETHShares); } /*////////////////////////////////////////////////////////////// internal functions //////////////////////////////////////////////////////////////*/ /// @notice internal function to remove node delegator contract address from queue /// @param nodeDelegatorAddress NodeDelegator contract address function _removeNodeDelegatorContractFromQueue(address nodeDelegatorAddress) internal { // 1. check if node delegator contract is in queue and find Index uint256 ndcIndex = _getNDCIndex(nodeDelegatorAddress); // 2. revert if node delegator contract has any asset balances. // 2.1 check if NDC has native ETH balance in eigen layer or/and in itself. _checkResidueEthBalance(nodeDelegatorAddress); // 2.2 check if NDC has LST balance _checkResidueLSTBalance(nodeDelegatorAddress); // 3. remove node delegator contract from queue // 3.1 remove from isNodeDelegator mapping isNodeDelegator[nodeDelegatorAddress] = 0; // 3.2 remove from nodeDelegatorQueue nodeDelegatorQueue[ndcIndex] = nodeDelegatorQueue[nodeDelegatorQueue.length - 1]; nodeDelegatorQueue.pop(); emit NodeDelegatorRemovedFromQueue(nodeDelegatorAddress); } function _getNDCIndex(address nodeDelegatorAddress) internal view returns (uint256) { uint256 length = nodeDelegatorQueue.length; uint256 i; for (; i < length;) { if (nodeDelegatorQueue[i] == nodeDelegatorAddress) { return i; } unchecked { ++i; } } // If node delegator contract is not found in queue, revert revert NodeDelegatorNotFound(); } /// @dev reverts if NDC has native ETH balance in eigen layer or in itself. function _checkResidueEthBalance(address nodeDelegatorAddress) internal view { if ( INodeDelegator(nodeDelegatorAddress).stakedButUnverifiedNativeETH() > 0 || INodeDelegator(nodeDelegatorAddress).getEffectivePodShares() != 0 || address(nodeDelegatorAddress).balance > maxNegligibleAmount ) { revert NodeDelegatorHasETH(); } } /// @dev reverts if NDC has LST balance function _checkResidueLSTBalance(address nodeDelegatorAddress) internal view { address[] memory supportedAssets = lrtConfig.getSupportedAssetList(); uint256 supportedAssetsLength = supportedAssets.length; uint256 assetBalance; for (uint256 i; i < supportedAssetsLength; ++i) { if (supportedAssets[i] == LRTConstants.ETH_TOKEN) { // this function only checks for residual LST balance continue; } assetBalance = IERC20(supportedAssets[i]).balanceOf(nodeDelegatorAddress) + INodeDelegator(nodeDelegatorAddress).getAssetBalance(supportedAssets[i]); if (assetBalance > maxNegligibleAmount) { revert NodeDelegatorHasAssetBalance(supportedAssets[i], assetBalance); } } } function _beforeDeposit( address asset, uint256 depositAmount, uint256 minRSETHAmountExpected ) private view returns (uint256 rsethAmountToMint) { if (depositAmount == 0 || depositAmount < minAmountToDeposit) { revert InvalidAmountToDeposit(); } if (_checkIfDepositAmountExceedesCurrentLimit(asset, depositAmount)) { revert MaximumDepositLimitReached(); } rsethAmountToMint = getRsETHAmountToMint(asset, depositAmount); if (rsethAmountToMint < minRSETHAmountExpected) { revert MinimumAmountToReceiveNotMet(); } } /// @notice checks if deposit amount exceeds current limit /// @param asset Asset address /// @param amount Asset amount /// @return bool true if deposit amount exceeds current limit function _checkIfDepositAmountExceedesCurrentLimit(address asset, uint256 amount) internal view returns (bool) { uint256 totalAssetDeposits = getTotalAssetDeposits(asset); if (asset == LRTConstants.ETH_TOKEN) { return (totalAssetDeposits > lrtConfig.depositLimitByAsset(asset)); } return (totalAssetDeposits + amount > lrtConfig.depositLimitByAsset(asset)); } /// @dev private function to mint rseth /// @param rsethAmountToMint Amount of rseth minted function _mintRsETH(uint256 rsethAmountToMint) private { address rsethToken = lrtConfig.rsETH(); // mint rseth for user IRSETH(rsethToken).mint(msg.sender, rsethAmountToMint); } }
Texte modifié
Ouvrir un fichier
// 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 { ILRTOracle } from "./interfaces/ILRTOracle.sol"; import { INodeDelegator } from "./interfaces/INodeDelegator.sol"; import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol"; import { ILRTUnstakingVault } from "./interfaces/ILRTUnstakingVault.sol"; import { ILRTConverter } from "./interfaces/ILRTConverter.sol"; import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol"; import { PausableUpgradeable } from "@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol"; import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol"; import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol"; import { ILido } from "./external/lido/ILido.sol"; /// @title LRTDepositPool - Deposit Pool Contract for LSTs /// @notice Handles LST asset deposits contract LRTDepositPool is ILRTDepositPool, LRTConfigRoleChecker, PausableUpgradeable, ReentrancyGuardUpgradeable { using SafeERC20 for IERC20; uint256 public maxNodeDelegatorLimit; uint256 public minAmountToDeposit; mapping(address => uint256) public isNodeDelegator; // 0: not a node delegator, 1: is a node delegator address[] public nodeDelegatorQueue; /// @notice maximum amount that can be ignored uint256 public maxNegligibleAmount; /// @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); __Pausable_init(); __ReentrancyGuard_init(); maxNodeDelegatorLimit = 10; lrtConfig = ILRTConfig(lrtConfigAddr); emit UpdatedLRTConfig(lrtConfigAddr); } /*////////////////////////////////////////////////////////////// receive functions //////////////////////////////////////////////////////////////*/ receive() external payable { } /// @dev receive from RewardReceiver function receiveFromRewardReceiver() external payable { } /// @dev receive from LRTConverter function receiveFromLRTConverter() external payable { } /// @dev receive from NodeDelegator function receiveFromNodeDelegator() external payable { } /*////////////////////////////////////////////////////////////// user interactions //////////////////////////////////////////////////////////////*/ /// @notice Allows user to deposit ETH to the protocol /// @param minRSETHAmountExpected Minimum amount of rseth to receive /// @param referralId referral id function depositETH( uint256 minRSETHAmountExpected, string calldata referralId ) external payable nonReentrant whenNotPaused onlySupportedAsset(LRTConstants.ETH_TOKEN) { // checks uint256 rsethAmountToMint = _beforeDeposit(LRTConstants.ETH_TOKEN, msg.value, minRSETHAmountExpected); // interactions _mintRsETH(rsethAmountToMint); emit ETHDeposit(msg.sender, msg.value, rsethAmountToMint, referralId); } /// @notice helps user stake LST to the protocol /// @param asset LST asset address to stake /// @param depositAmount LST asset amount to stake /// @param minRSETHAmountExpected Minimum amount of rseth to receive function depositAsset( address asset, uint256 depositAmount, uint256 minRSETHAmountExpected, string calldata referralId ) external nonReentrant whenNotPaused onlySupportedERC20Token(asset) { // checks uint256 rsethAmountToMint = _beforeDeposit(asset, depositAmount, minRSETHAmountExpected); // interactions IERC20(asset).safeTransferFrom(msg.sender, address(this), depositAmount); _mintRsETH(rsethAmountToMint); emit AssetDeposit(msg.sender, asset, depositAmount, rsethAmountToMint, referralId); } /*////////////////////////////////////////////////////////////// Fund movement functions //////////////////////////////////////////////////////////////*/ /// @notice swap ETH for LST asset which is accepted by LRTDepositPool /// @dev use LRTOracle to get price for toToken. Only callable by LRT manager /// @param toAsset Asset address to swap to /// @param minToAssetAmount Minimum asset amount to swap to function swapETHForAssetWithinDepositPool( address toAsset, uint256 minToAssetAmount ) external payable nonReentrant onlyLRTOperator onlySupportedERC20Token(toAsset) { // checks uint256 ethAmountSent = msg.value; if (ethAmountSent == 0) { revert ZeroAssetAmount(); } uint256 returnAmount = getSwapETHToAssetReturnAmount(toAsset, ethAmountSent); if (minToAssetAmount > returnAmount) { revert MinAssetAmountNotMet(); } if (IERC20(toAsset).balanceOf(address(this)) < returnAmount) { revert NotEnoughAssetToTransfer(); } // interactions IERC20(toAsset).safeTransfer(msg.sender, returnAmount); emit ETHSwappedForLST(ethAmountSent, toAsset, returnAmount); } /// @notice swap LST Asset for ETH which is accepted by LRTDepositPool /// @dev use LRTOracle to get price for fromAsset. Only callable by LRT operator /// @param fromAsset Asset address to swap from /// @param fromAssetAmount Asset amount to swap from /// @param minETHAmountExpected Minimum ETH amount to swap to function swapAssetForETHWithinDepositPool( address fromAsset, uint256 fromAssetAmount, uint256 minETHAmountExpected ) external nonReentrant onlyLRTOperator onlySupportedERC20Token(fromAsset) { if (fromAssetAmount == 0) { revert ZeroAssetAmount(); } // checks uint256 returnAmount = getSwapAssetForETHReturnAmount(fromAsset, fromAssetAmount); if (minETHAmountExpected > returnAmount) { revert MinAssetAmountNotMet(); } if (address(this).balance < returnAmount) { revert NotEnoughETHToTransfer(); } IERC20(fromAsset).safeTransferFrom(msg.sender, address(this), fromAssetAmount); (bool success,) = payable(msg.sender).call{ value: returnAmount }(""); if (!success) revert EthTransferFailed(); emit AssetSwappedForETH(fromAsset, fromAssetAmount, returnAmount); } /// @notice transfers asset lying in this DepositPool to node delegator contract /// @dev only callable by LRT Operator /// @param ndcIndex Index of NodeDelegator contract address in nodeDelegatorQueue /// @param asset Asset address /// @param amount Asset amount to transfer function transferAssetToNodeDelegator( uint256 ndcIndex, address asset, uint256 amount ) external nonReentrant onlyLRTOperator onlySupportedERC20Token(asset) { address nodeDelegator = nodeDelegatorQueue[ndcIndex]; IERC20(asset).safeTransfer(nodeDelegator, amount); } /// @notice transfers ETH lying in this DepositPool to node delegator contract /// @dev only callable by LRT Operator /// @param ndcIndex Index of NodeDelegator contract address in nodeDelegatorQueue /// @param amount ETH amount to transfer function transferETHToNodeDelegator( uint256 ndcIndex, uint256 amount ) external nonReentrant onlyLRTOperator onlySupportedAsset(LRTConstants.ETH_TOKEN) { address nodeDelegator = nodeDelegatorQueue[ndcIndex]; INodeDelegator(nodeDelegator).sendETHFromDepositPoolToNDC{ value: amount }(); emit EthTransferred(nodeDelegator, amount); } /// @notice transfers asset lying in this DepositPool to LRTUnstakingVault contract /// @dev only callable by LRT Operator /// @param asset Asset address /// @param amount Asset amount to transfer function transferAssetToLRTUnstakingVault( address asset, uint256 amount ) external nonReentrant onlyLRTOperator onlySupportedERC20Token(asset) { address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); IERC20(asset).safeTransfer(lrtUnstakingVault, amount); } /// @notice transfers ETH lying in this DepositPool to nLRTUnstakingVault contract /// @dev only callable by LRT Operator /// @param amount ETH amount to transfer function transferETHToLRTUnstakingVault(uint256 amount) external nonReentrant onlyLRTOperator onlySupportedAsset(LRTConstants.ETH_TOKEN) { address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); ILRTUnstakingVault(lrtUnstakingVault).receiveFromLRTDepositPool{ value: amount }(); emit EthTransferred(lrtUnstakingVault, amount); } /*////////////////////////////////////////////////////////////// Setters / Update Functions //////////////////////////////////////////////////////////////*/ /// @notice maximum amount that can be ignored /// @dev only callable by LRT admin /// @param maxNegligibleAmount_ Maximum amount that can be ignored function setMaxNegligibleAmount(uint256 maxNegligibleAmount_) external onlyLRTAdmin { maxNegligibleAmount = maxNegligibleAmount_; emit MaxNegligibleAmountUpdated(maxNegligibleAmount_); } /// @notice update min amount to deposit /// @dev only callable by LRT admin /// @param minAmountToDeposit_ Minimum amount to deposit function setMinAmountToDeposit(uint256 minAmountToDeposit_) external onlyLRTAdmin { minAmountToDeposit = minAmountToDeposit_; emit MinAmountToDepositUpdated(minAmountToDeposit_); } /// @notice update max node delegator count /// @dev only callable by LRT admin /// @param maxNodeDelegatorLimit_ Maximum count of node delegator function updateMaxNodeDelegatorLimit(uint256 maxNodeDelegatorLimit_) external onlyLRTAdmin { if (maxNodeDelegatorLimit_ < nodeDelegatorQueue.length) { revert InvalidMaximumNodeDelegatorLimit(); } maxNodeDelegatorLimit = maxNodeDelegatorLimit_; emit MaxNodeDelegatorLimitUpdated(maxNodeDelegatorLimit); } /// @notice add new node delegator contract addresses /// @dev only callable by LRT admin /// @param nodeDelegatorContracts Array of NodeDelegator contract addresses function addNodeDelegatorContractToQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin { uint256 length = nodeDelegatorContracts.length; if (nodeDelegatorQueue.length + length > maxNodeDelegatorLimit) { revert MaximumNodeDelegatorLimitReached(); } for (uint256 i; i < length;) { UtilLib.checkNonZeroAddress(nodeDelegatorContracts[i]); // check if node delegator contract is already added and add it if not if (isNodeDelegator[nodeDelegatorContracts[i]] == 0) { nodeDelegatorQueue.push(nodeDelegatorContracts[i]); emit NodeDelegatorAddedinQueue(nodeDelegatorContracts[i]); } isNodeDelegator[nodeDelegatorContracts[i]] = 1; unchecked { ++i; } } } /// @notice remove node delegator contract address from queue /// @dev only callable by LRT admin /// @param nodeDelegatorAddress NodeDelegator contract address function removeNodeDelegatorContractFromQueue(address nodeDelegatorAddress) external onlyLRTAdmin { _removeNodeDelegatorContractFromQueue(nodeDelegatorAddress); } /// @notice remove many node delegator contracts from queue /// @dev only callable by LRT admin /// @param nodeDelegatorContracts Array of NodeDelegator contract addresses function removeManyNodeDelegatorContractsFromQueue(address[] calldata nodeDelegatorContracts) external onlyLRTAdmin { uint256 length = nodeDelegatorContracts.length; for (uint256 i; i < length;) { _removeNodeDelegatorContractFromQueue(nodeDelegatorContracts[i]); unchecked { ++i; } } } /// @dev Triggers stopped state. Contract must not be paused. function pause() external onlyRole(LRTConstants.PAUSER_ROLE) { _pause(); } /// @dev Returns to normal state. Contract must be paused function unpause() external onlyLRTAdmin { _unpause(); } /*////////////////////////////////////////////////////////////// other write functions //////////////////////////////////////////////////////////////*/ /// @notice Approves the maximum amount of an asset to the LRTConverter contract /// @dev only supported assets can be deposited and only called by the LRT manager /// @param asset the asset to approve function maxApproveToLRTConverter(address asset) external onlySupportedERC20Token(asset) onlyLRTManager { address lrtConverterAddress = lrtConfig.getContract(LRTConstants.LRT_CONVERTER); IERC20(asset).forceApprove(lrtConverterAddress, type(uint256).max); } /// @notice Revokes the approval of an asset to the LRTConverter contract /// @dev only supported assets can be deposited and only called by the LRT manager /// @param asset the asset to revoke approval for function revokeApproveToLRTConverter(address asset) external onlySupportedERC20Token(asset) onlyLRTManager { address lrtConverterAddress = lrtConfig.getContract(LRTConstants.LRT_CONVERTER); IERC20(asset).forceApprove(lrtConverterAddress, 0); } /*////////////////////////////////////////////////////////////// view functions //////////////////////////////////////////////////////////////*/ /// @notice gets the total asset present in protocol /// @param asset Asset address /// @return totalAssetDeposit total asset present in protocol function getTotalAssetDeposits(address asset) public view override returns (uint256 totalAssetDeposit) { ( uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer, uint256 assetUnstakingFromEigenLayer, uint256 assetLyingInConverter, uint256 assetLyingUnstakingVault ) = getAssetDistributionData(asset); uint256 effectiveAssetWithEigenLayer = assetStakedInEigenLayer + assetUnstakingFromEigenLayer; return (assetLyingInDepositPool + assetLyingInNDCs + effectiveAssetWithEigenLayer + assetLyingInConverter + assetLyingUnstakingVault); } /// @notice gets the current limit of asset deposit /// @param asset Asset address /// @return currentLimit Current limit of asset deposit function getAssetCurrentLimit(address asset) public view override returns (uint256) { uint256 totalAssetDeposits = getTotalAssetDeposits(asset); if (totalAssetDeposits > lrtConfig.depositLimitByAsset(asset)) { return 0; } return lrtConfig.depositLimitByAsset(asset) - totalAssetDeposits; } /// @dev get node delegator queue /// @return nodeDelegatorQueue Array of node delegator contract addresses function getNodeDelegatorQueue() external view override returns (address[] memory) { return nodeDelegatorQueue; } /// @dev provides asset amount distribution data among depositPool, NDCs and eigenLayer /// @param asset the asset to get the total amount of /// @return assetLyingInDepositPool asset amount lying in this LRTDepositPool contract /// @return assetLyingInNDCs asset amount sum lying in all NDC contract /// @return assetStakedInEigenLayer asset amount deposited in eigen layer strategies through all NDCs /// @return assetUnstakingFromEigenLayer asset amount in delayed withdrawal from eigen layer strategies through all /// NDCs /// @return assetLyingInConverter asset value lying in converter /// @return assetLyingUnstakingVault asset amount lying in UnstakingVault function getAssetDistributionData(address asset) public view override onlySupportedAsset(asset) returns ( uint256 assetLyingInDepositPool, uint256 assetLyingInNDCs, uint256 assetStakedInEigenLayer, uint256 assetUnstakingFromEigenLayer, uint256 assetLyingInConverter, uint256 assetLyingUnstakingVault ) { if (asset == LRTConstants.ETH_TOKEN) { return getETHDistributionData(); } assetLyingInDepositPool = IERC20(asset).balanceOf(address(this)); // NOTE: For legacy el withdrawal support, this can be removed after all pre slashing withdrawals are processed assetUnstakingFromEigenLayer = ILRTUnstakingVault(lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT)).getAssetsUnstaking(asset); uint256 ndcsCount = nodeDelegatorQueue.length; for (uint256 i; i < ndcsCount;) { assetLyingInNDCs += IERC20(asset).balanceOf(nodeDelegatorQueue[i]); assetStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetBalance(asset); assetUnstakingFromEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getAssetUnstaking(asset); unchecked { ++i; } } address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); assetLyingInConverter = 0; // assets in converter are accounted in their eth value => getETHDistributionData() assetLyingUnstakingVault = IERC20(asset).balanceOf(lrtUnstakingVault); } /// @dev provides ETH amount distribution data among depositPool, NDCs and eigenLayer /// @dev rewards are not accounted here /// it will automatically be accounted once it is moved from feeReceiver/rewardReceiver to depositPool function getETHDistributionData() public view override returns ( uint256 ethLyingInDepositPool, uint256 ethLyingInNDCs, uint256 ethStakedInEigenLayer, uint256 ethUnstakingFromEigenLayer, uint256 ethLyingInConverter, uint256 ethLyingInUnstakingVault ) { ethLyingInDepositPool = address(this).balance; uint256 ndcsCount = nodeDelegatorQueue.length; ethUnstakingFromEigenLayer = ILRTUnstakingVault(lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT)) .getAssetsUnstaking(LRTConstants.ETH_TOKEN); for (uint256 i; i < ndcsCount;) { ethLyingInNDCs += nodeDelegatorQueue[i].balance; ethStakedInEigenLayer += INodeDelegator(nodeDelegatorQueue[i]).getEffectivePodShares(); ethUnstakingFromEigenLayer += INodeDelegator(nodeDelegatorQueue[i]) .getAssetUnstaking(LRTConstants.ETH_TOKEN); unchecked { ++i; } } address lrtUnstakingVault = lrtConfig.getContract(LRTConstants.LRT_UNSTAKING_VAULT); ethLyingInUnstakingVault = lrtUnstakingVault.balance; address lrtConverter = lrtConfig.getContract(LRTConstants.LRT_CONVERTER); ethLyingInConverter = ILRTConverter(lrtConverter).ethValueInWithdrawal(); } /// @notice View amount of rsETH to mint for given asset amount /// @param asset Asset address /// @param amount Asset amount /// @return rsethAmountToMint Amount of rseth to mint function getRsETHAmountToMint( address asset, uint256 amount ) public view override returns (uint256 rsethAmountToMint) { // setup oracle contract address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); // calculate rseth amount to mint based on asset amount and asset exchange rate rsethAmountToMint = (amount * lrtOracle.getAssetPrice(asset)) / lrtOracle.rsETHPrice(); } /// @notice get return amount for swapping ETH to asset that is accepted by LRTDepositPool /// @dev use LRTOracle to get price for toToken /// @param toAsset Asset address to swap to /// @param ethAmountToSend Eth amount to swap from /// @return returnAmount Return amount of toAsset function getSwapETHToAssetReturnAmount( address toAsset, uint256 ethAmountToSend ) public view returns (uint256 returnAmount) { address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); uint256 ethPricePerUint = 1e18; return ethPricePerUint * ethAmountToSend / lrtOracle.getAssetPrice(toAsset); } /// @notice get return amount for swapping asset to ETH that is accepted by LRTDepositPool /// @dev use LRTOracle to get price for fromAsset /// @param fromAsset Asset address to swap from /// @param fromAssetAmount Asset amount to swap from /// @return returnAmount Return amount of ETH function getSwapAssetForETHReturnAmount( address fromAsset, uint256 fromAssetAmount ) public view returns (uint256 returnAmount) { address lrtOracleAddress = lrtConfig.getContract(LRTConstants.LRT_ORACLE); ILRTOracle lrtOracle = ILRTOracle(lrtOracleAddress); return lrtOracle.getAssetPrice(fromAsset) * fromAssetAmount / 1e18; } /// @notice Stakes ETH with Lido to receive stETH /// @param referral Optional referral address for Lido function stakeEthForStETH(address referral, uint256 ethAmount) external onlyLRTManager { address stETHAddress = lrtConfig.getLSTToken(LRTConstants.ST_ETH_TOKEN); uint256 stETHShares = ILido(stETHAddress).submit{ value: ethAmount }(referral); emit AssetStaked(stETHAddress, ethAmount, stETHShares); } /*////////////////////////////////////////////////////////////// internal functions //////////////////////////////////////////////////////////////*/ /// @notice internal function to remove node delegator contract address from queue /// @param nodeDelegatorAddress NodeDelegator contract address function _removeNodeDelegatorContractFromQueue(address nodeDelegatorAddress) internal { // 1. check if node delegator contract is in queue and find Index uint256 ndcIndex = _getNDCIndex(nodeDelegatorAddress); // 2. revert if node delegator contract has any asset balances. // 2.1 check if NDC has native ETH balance in eigen layer or/and in itself. _checkResidueEthBalance(nodeDelegatorAddress); // 2.2 check if NDC has LST balance _checkResidueLSTBalance(nodeDelegatorAddress); // 3. remove node delegator contract from queue // 3.1 remove from isNodeDelegator mapping isNodeDelegator[nodeDelegatorAddress] = 0; // 3.2 remove from nodeDelegatorQueue nodeDelegatorQueue[ndcIndex] = nodeDelegatorQueue[nodeDelegatorQueue.length - 1]; nodeDelegatorQueue.pop(); emit NodeDelegatorRemovedFromQueue(nodeDelegatorAddress); } function _getNDCIndex(address nodeDelegatorAddress) internal view returns (uint256) { uint256 length = nodeDelegatorQueue.length; uint256 i; for (; i < length;) { if (nodeDelegatorQueue[i] == nodeDelegatorAddress) { return i; } unchecked { ++i; } } // If node delegator contract is not found in queue, revert revert NodeDelegatorNotFound(); } /// @dev reverts if NDC has native ETH balance in eigen layer or in itself. function _checkResidueEthBalance(address nodeDelegatorAddress) internal view { if ( INodeDelegator(nodeDelegatorAddress).getEffectivePodShares() != 0 || address(nodeDelegatorAddress).balance > maxNegligibleAmount || INodeDelegator(nodeDelegatorAddress).getAssetUnstaking(LRTConstants.ETH_TOKEN) > 0 ) { revert NodeDelegatorHasETH(); } } /// @dev reverts if NDC has LST balance function _checkResidueLSTBalance(address nodeDelegatorAddress) internal view { address[] memory supportedAssets = lrtConfig.getSupportedAssetList(); uint256 supportedAssetsLength = supportedAssets.length; uint256 assetBalance; for (uint256 i; i < supportedAssetsLength; ++i) { if (supportedAssets[i] == LRTConstants.ETH_TOKEN) { // this function only checks for residual LST balance continue; } assetBalance = IERC20(supportedAssets[i]).balanceOf(nodeDelegatorAddress) + INodeDelegator(nodeDelegatorAddress).getAssetBalance(supportedAssets[i]); assetBalance += INodeDelegator(nodeDelegatorAddress).getAssetUnstaking(supportedAssets[i]); if (assetBalance > maxNegligibleAmount) { revert NodeDelegatorHasAssetBalance(supportedAssets[i], assetBalance); } } } function _beforeDeposit( address asset, uint256 depositAmount, uint256 minRSETHAmountExpected ) private view returns (uint256 rsethAmountToMint) { if (depositAmount == 0 || depositAmount < minAmountToDeposit) { revert InvalidAmountToDeposit(); } if (_checkIfDepositAmountExceedesCurrentLimit(asset, depositAmount)) { revert MaximumDepositLimitReached(); } rsethAmountToMint = getRsETHAmountToMint(asset, depositAmount); if (rsethAmountToMint < minRSETHAmountExpected) { revert MinimumAmountToReceiveNotMet(); } } /// @notice checks if deposit amount exceeds current limit /// @param asset Asset address /// @param amount Asset amount /// @return bool true if deposit amount exceeds current limit function _checkIfDepositAmountExceedesCurrentLimit(address asset, uint256 amount) internal view returns (bool) { uint256 totalAssetDeposits = getTotalAssetDeposits(asset); if (asset == LRTConstants.ETH_TOKEN) { return (totalAssetDeposits > lrtConfig.depositLimitByAsset(asset)); } return (totalAssetDeposits + amount > lrtConfig.depositLimitByAsset(asset)); } /// @dev private function to mint rseth /// @param rsethAmountToMint Amount of rseth minted function _mintRsETH(uint256 rsethAmountToMint) private { address rsethToken = lrtConfig.rsETH(); // mint rseth for user IRSETH(rsethToken).mint(msg.sender, rsethAmountToMint); } }
Trouver la différence