LRTConverter

Creado El diff nunca expira
51 eliminaciones
196 líneas
134 adiciones
272 líneas
// SPDX-License-Identifier: BUSL-1.1
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.21;
pragma solidity 0.8.27;


import { LRTConstants } from "./utils/LRTConstants.sol";
import { LRTConstants } from "./utils/LRTConstants.sol";


import { UtilLib } from "./utils/UtilLib.sol";
import { UtilLib } from "./utils/UtilLib.sol";
import { LRTConfigRoleChecker, ILRTConfig } from "./utils/LRTConfigRoleChecker.sol";
import { LRTConfigRoleChecker, ILRTConfig } from "./utils/LRTConfigRoleChecker.sol";


import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol";
import { ILRTDepositPool } from "./interfaces/ILRTDepositPool.sol";
import { ILRTOracle } from "./interfaces/ILRTOracle.sol";
import { ILRTOracle } from "./interfaces/ILRTOracle.sol";
import { ILRTConverter } from "./interfaces/ILRTConverter.sol";
import { ILRTConverter } from "./interfaces/ILRTConverter.sol";
import { ILRTWithdrawalManager } from "./interfaces/ILRTWithdrawalManager.sol";


import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import { IERC721Receiver } from "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { IERC20 } from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import { SafeERC20 } from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {

ReentrancyGuardUpgradeable
import { ReentrancyGuardUpgradeable } from "@openzeppelin/contracts-upgradeable/security/ReentrancyGuardUpgradeable.sol";
} 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 { UnstakeStETH } from "./unstaking-adapters/UnstakeStETH.sol";
import { UnstakeStETH } from "./unstaking-adapters/UnstakeStETH.sol";

/// @dev Legacy unstaking adapters for swETH are kept for upgrade compatibility
import { UnstakeSwETH } from "./unstaking-adapters/UnstakeSwETH.sol";
import { UnstakeSwETH } from "./unstaking-adapters/UnstakeSwETH.sol";


/// @title LRTConverter - Unstakes LSTs to ETH and swaps ETH to LSTs
/// @title LRTConverter - Unstakes LSTs to ETH and swaps ETH to LSTs
/// @notice This contract is responsible for unstaking LSTs to ETH and swapping ETH to LSTs
/// @notice This contract is responsible for unstaking LSTs to ETH and swapping ETH to LSTs
contract LRTConverter is
contract LRTConverter is
ILRTConverter,
ILRTConverter,
LRTConfigRoleChecker,
LRTConfigRoleChecker,
ReentrancyGuardUpgradeable,
ReentrancyGuardUpgradeable,
UnstakeSwETH,
UnstakeSwETH,
UnstakeStETH,
UnstakeStETH,
IERC721Receiver
IERC721Receiver
{
{
using SafeERC20 for IERC20;
using SafeERC20 for IERC20;


mapping(bytes32 => bool) public _legacyProcessedWithdrawalRoots;
mapping(bytes32 => bool) public _legacyProcessedWithdrawalRoots;
mapping(address => bool) public convertableAssets;
mapping(address => bool) public _legacyConvertibleAssets;
mapping(address => uint256) public _legacyConversionLimit;
mapping(address => uint256) public _legacyConversionLimit;


//needs to be added to total assets in protocol
// needs to be added to total assets in protocol
uint256 public ethValueInWithdrawal;
uint256 public ethValueInWithdrawal;


modifier onlyConvertableAsset(address asset) {
mapping(address => bool) private whitelistedUsers;
require(convertableAssets[asset], "Asset not supported");

uint256 public whitelistedUnstakeAllowance;

modifier onlyWhitelistedUser() {
if (!isUserWhitelisted(msg.sender)) {
revert UserNotWhitelisted();
}
_;
}

/// @dev Modifier to enforce unstaking limits and update counters
/// @param amountToUnstake Amount of stETH to unstake
modifier withinUnstakeLimits(uint256 amountToUnstake) {
if (amountToUnstake == 0) {
revert InvalidAmount();
}

uint256 availableActiveETHWithdrawals = _getActiveETHUserWithdrawals();

if (amountToUnstake > whitelistedUnstakeAllowance + availableActiveETHWithdrawals) {
revert UnstakeLimitExceeded();
}

// Consume intended withdrawal limit
if (whitelistedUnstakeAllowance > 0) {
uint256 whitelistedAmountConsumed =
amountToUnstake > whitelistedUnstakeAllowance ? whitelistedUnstakeAllowance : amountToUnstake;

whitelistedUnstakeAllowance -= whitelistedAmountConsumed;
}
_;
_;
}
}


/// @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);
__ReentrancyGuard_init();
__ReentrancyGuard_init();
lrtConfig = ILRTConfig(lrtConfigAddr);
lrtConfig = ILRTConfig(lrtConfigAddr);
emit UpdatedLRTConfig(lrtConfigAddr);
emit UpdatedLRTConfig(lrtConfigAddr);
}
}


/// @dev Initializes the contract
/// @dev Initializes the contract
/// @param _withdrawalQueueAddress Address of withdrawal queue (stETH)
/// @param _withdrawalQueueAddress Address of withdrawal queue (stETH)
/// @param _stETHAddress Address of stETH
/// @param _stETHAddress Address of stETH
/// @param _swEXITAddress Address of swEXIT (swETH)
/// @param _swEXITAddress Address of swEXIT (swETH)
/// @param _swETHAddress Address of swETH
/// @param _swETHAddress Address of swETH
function initialize2(
function initialize2(
address _withdrawalQueueAddress,
address _withdrawalQueueAddress,
address _stETHAddress,
address _stETHAddress,
address _swEXITAddress,
address _swEXITAddress,
address _swETHAddress
address _swETHAddress
)
)
external
external
reinitializer(2)
reinitializer(2)
onlyLRTAdmin
onlyLRTAdmin
{
{
__ReentrancyGuard_init();
__ReentrancyGuard_init();
__initializeSwETH(_swEXITAddress, _swETHAddress);
__initializeSwETH(_swEXITAddress, _swETHAddress);
__initializeStETH(_withdrawalQueueAddress, _stETHAddress);
__initializeStETH(_withdrawalQueueAddress, _stETHAddress);
}
}


function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) {
function onERC721Received(address, address, uint256, bytes calldata) external pure returns (bytes4) {
return this.onERC721Received.selector;
return this.onERC721Received.selector;
}
}


/// @dev fallback to receive funds
/// @dev fallback to receive funds
receive() external payable { }
receive() external payable { }


/*////////////////////////////////////////////////////////////
/*////////////////////////////////////////////////////////////
write interactions
write interactions
//////////////////////////////////////////////////////////////*/
//////////////////////////////////////////////////////////////*/


/// @notice swap ETH for LST asset which is accepted by LRTConverter and send to LRTDepositPool
/// @dev use LRTOracle to get price for asset. Only callable by LRT Operator
/// @param asset Asset address to swap to
/// @param minimumExpectedReturnAmount Minimum asset amount to swap to
function swapEthToAsset(
address asset,
uint256 minimumExpectedReturnAmount
)
external
payable
onlyLRTOperator
onlyConvertableAsset(asset)
returns (uint256 returnAmount)
{
ILRTDepositPool lrtDepositPool = ILRTDepositPool(lrtConfig.getContract(LRTConstants.LRT_DEPOSIT_POOL));
uint256 ethAmountSent = msg.value;

returnAmount = lrtDepositPool.getSwapETHToAssetReturnAmount(asset, ethAmountSent);

if (returnAmount < minimumExpectedReturnAmount || IERC20(asset).balanceOf(address(this)) < returnAmount) {
revert NotEnoughAssetToTransfer();
}
// account for limits and the asset value in contract
_sendEthToDepositPool(ethAmountSent);

IERC20(asset).safeTransfer(msg.sender, returnAmount);
emit ETHSwappedForLST(ethAmountSent, asset, returnAmount);
}

/// @notice send asset from deposit pool to LRTConverter
/// @notice send asset from deposit pool to LRTConverter
/// @dev Only callable by LRT Operator and asset need to be approved
/// @dev Only callable by LRT Operator and asset need to be approved
/// @param _asset Asset address to send
/// @param _asset Asset address to send
/// @param _amount Asset amount to send
/// @param _amount Asset amount to send
function transferAssetFromDepositPool(
function transferAssetFromDepositPool(
address _asset,
address _asset,
uint256 _amount
uint256 _amount
)
)
external
external