diff --git a/contracts/SDCollateral.sol b/contracts/SDCollateral.sol index 3c898956..b1b232be 100644 --- a/contracts/SDCollateral.sol +++ b/contracts/SDCollateral.sol @@ -255,7 +255,7 @@ contract SDCollateral is ISDCollateral, AccessControlUpgradeable, ReentrancyGuar // HELPER function getOperatorInfo(address _operator) - internal + public view returns ( uint8 _poolId, diff --git a/contracts/SDIncentiveController.sol b/contracts/SDIncentiveController.sol index b4b13ef4..e94c0372 100644 --- a/contracts/SDIncentiveController.sol +++ b/contracts/SDIncentiveController.sol @@ -6,6 +6,7 @@ import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import './library/UtilLib.sol'; import './interfaces/IStaderConfig.sol'; +import './interfaces/ISDUtilityPool.sol'; import './interfaces/ISDIncentiveController.sol'; /// @title SDIncentiveController @@ -70,20 +71,19 @@ contract SDIncentiveController is ISDIncentiveController, AccessControlUpgradeab /// @notice Calculates the current reward per token. /// @return The calculated reward per token. function rewardPerToken() public view returns (uint256) { - if (IERC20(staderConfig.getSDxToken()).totalSupply() == 0) { + uint256 totalSupply = ISDUtilityPool(staderConfig.getSDUtilityPool()).cTokenTotalSupply(); + if (totalSupply == 0) { return rewardPerTokenStored; } return - rewardPerTokenStored + - (((block.number - lastUpdateBlockNumber) * emissionPerBlock * 1e18) / - IERC20(staderConfig.getSDxToken()).totalSupply()); + rewardPerTokenStored + (((block.number - lastUpdateBlockNumber) * emissionPerBlock * 1e18) / totalSupply); } /// @notice Calculates the total accrued reward for an account. /// @param account The account to calculate rewards for. /// @return The total accrued reward for the account. function earned(address account) public view returns (uint256) { - uint256 currentBalance = IERC20(staderConfig.getSDxToken()).balanceOf(account); + uint256 currentBalance = ISDUtilityPool(staderConfig.getSDUtilityPool()).delegatorCTokenBalance(account); uint256 currentRewardPerToken = rewardPerToken(); return ((currentBalance * (currentRewardPerToken - userRewardPerTokenPaid[account])) / 1e18) + rewards[account]; diff --git a/contracts/SDUtilityPool.sol b/contracts/SDUtilityPool.sol index c36e1ecd..2a777e17 100644 --- a/contracts/SDUtilityPool.sol +++ b/contracts/SDUtilityPool.sol @@ -2,17 +2,19 @@ pragma solidity 0.8.16; import './library/UtilLib.sol'; -import './SDX.sol'; import './interfaces/IStaderConfig.sol'; import './interfaces/ISDIncentiveController.sol'; import './interfaces/ISDUtilityPool.sol'; import './interfaces/SDCollateral/ISDCollateral.sol'; +import '@openzeppelin/contracts/utils/math/Math.sol'; import '@openzeppelin/contracts/token/ERC20/IERC20.sol'; import '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol'; import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol'; contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgradeable { + using Math for uint256; + uint256 constant DECIMAL = 1e18; /** @@ -41,10 +43,21 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr */ uint256 public totalProtocolFee; - uint256 public utilizationRate; + uint256 public utilizationRatePerBlock; + + uint256 public cTokenTotalSupply; uint256 public maxETHWorthOfSDPerValidator; + uint256 public nextRequestIdToFinalize; + uint256 public nextRequestId; + uint256 public sdRequestedForWithdraw; + uint256 public finalizationBatchLimit; + uint256 public sdReservedForClaim; + + //upper cap on user non redeemed withdraw request count + uint256 public maxNonRedeemedDelegatorRequestCount; + bytes32 public constant NODE_REGISTRY_CONTRACT = keccak256('NODE_REGISTRY_CONTRACT'); IStaderConfig public staderConfig; @@ -54,8 +67,22 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr uint256 utilizeIndex; } + /// @notice structure representing a user request for withdrawal. + struct DelegatorWithdrawInfo { + address owner; // address that can claim on behalf of this request + uint256 amountOfCToken; //amount of CToken to withdraw + uint256 amountOfSD; //amount of SD to withdraw + uint256 requestBlock; // block number of withdraw request + } + mapping(address => UtilizerStruct) public utilizerData; + mapping(address => uint256) public delegatorCTokenBalance; + + mapping(uint256 => DelegatorWithdrawInfo) public delegatorWithdrawRequests; + + mapping(address => uint256[]) public requestIdsByDelegatorAddress; + /// @custom:oz-upgrades-unsafe-allow constructor constructor() { _disableInitializers(); @@ -69,8 +96,11 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr __Pausable_init(); staderConfig = IStaderConfig(_staderConfig); utilizeIndex = DECIMAL; - utilizationRate = 0; + utilizationRatePerBlock = 0; protocolFeeFactor = 0; + nextRequestId = 1; + nextRequestIdToFinalize = 1; + finalizationBatchLimit = 50; accrualBlockNumber = block.number; maxETHWorthOfSDPerValidator = 1 ether; _grantRole(DEFAULT_ADMIN_ROLE, _admin); @@ -89,19 +119,117 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr } /** - * @notice Sender redeems SDx in exchange for the SD token - * @dev Accrues fee whether or not the operation succeeds, unless reverted - * @param sdXAmount The number of SDx to redeem + * @notice auxiliary method to put a withdrawal request + * @param _cTokenAmount amount of cToken to withdraw + * @return _requestId generated request ID for withdrawal */ - function redeem(uint256 sdXAmount) external { + function requestWithdraw(uint256 _cTokenAmount) external returns (uint256 _requestId) { + if (_cTokenAmount > delegatorCTokenBalance[msg.sender]) { + revert InvalidAmountOfWithdraw(); + } accrueFee(); - _redeem(sdXAmount); + uint256 exchangeRate = _exchangeRateStoredInternal(); + uint256 sdRequested = (exchangeRate * _cTokenAmount) / DECIMAL; + _requestId = _requestWithdraw(sdRequested, _cTokenAmount); + } + + /** + * @notice auxiliary method to put a withdrawal request + * @param _sdAmount amount of SD to withdraw + * @return _requestId generated request ID for withdrawal + */ + function requestWithdrawWithSDAmount(uint256 _sdAmount) external returns (uint256 _requestId) { + accrueFee(); + uint256 exchangeRate = _exchangeRateStoredInternal(); + uint256 cTokenToBurn = (_sdAmount * DECIMAL) / exchangeRate; + if (cTokenToBurn > delegatorCTokenBalance[msg.sender]) { + revert InvalidAmountOfWithdraw(); + } + _requestId = _requestWithdraw(_sdAmount, cTokenToBurn); + } + + /** + * @notice finalize delegator's withdraw requests + */ + function finalizeDelegatorWithdrawalRequest() external { + uint256 maxRequestIdToFinalize = Math.min(nextRequestId, nextRequestIdToFinalize + finalizationBatchLimit) - 1; + uint256 requestId; + uint256 sdToReserveToFinalizeRequest; + uint256 availableSDInPool = getPoolAvailableSDBalance(); + for (requestId = nextRequestIdToFinalize; requestId <= maxRequestIdToFinalize; ) { + DelegatorWithdrawInfo memory delegatorWithdrawInfo = delegatorWithdrawRequests[requestId]; + uint256 requiredSD = delegatorWithdrawInfo.amountOfSD; + if ( + (sdToReserveToFinalizeRequest + requiredSD > availableSDInPool) || + (delegatorWithdrawInfo.requestBlock + staderConfig.getMinBlockDelayToFinalizeWithdrawRequest() > + block.number) + ) { + break; + } + sdRequestedForWithdraw -= requiredSD; + sdToReserveToFinalizeRequest += requiredSD; + delegatorCTokenBalance[delegatorWithdrawInfo.owner] -= delegatorWithdrawInfo.amountOfCToken; + cTokenTotalSupply -= delegatorWithdrawInfo.amountOfCToken; + unchecked { + ++requestId; + } + } + // at here, upto (requestId-1) is finalized + if (requestId > nextRequestIdToFinalize) { + nextRequestIdToFinalize = requestId; + sdReservedForClaim += sdToReserveToFinalizeRequest; + } + } + + /** + * @notice transfer the eth of finalized request to recipient and delete the request + * @param _requestId request id to redeem + */ + function claim(uint256 _requestId) external { + if (_requestId >= nextRequestIdToFinalize) { + revert requestIdNotFinalized(_requestId); + } + DelegatorWithdrawInfo memory delegatorRequest = delegatorWithdrawRequests[_requestId]; + if (msg.sender != delegatorRequest.owner) { + revert CallerNotAuthorizedToRedeem(); + } + uint256 sdToTransfer = delegatorRequest.amountOfSD; + _deleteRequestId(_requestId); + if (!IERC20(staderConfig.getStaderToken()).transferFrom(address(this), msg.sender, sdToTransfer)) { + revert SDTransferFailed(); + } + emit RequestRedeemed(msg.sender, sdToTransfer); + } + + /// @notice return the list of ongoing withdraw requestIds for a user + function getRequestIdsByDelegator(address _delegator) external view returns (uint256[] memory) { + return requestIdsByDelegatorAddress[_delegator]; } /** * @notice Sender utilize SD from the protocol to add it as collateral to run validators * @param utilizeAmount The amount of the SD token to utilize */ + function utilize(uint256 utilizeAmount) external { + ISDCollateral sdCollateral = ISDCollateral(staderConfig.getSDCollateral()); + (, , uint256 nonTerminalKeyCount) = sdCollateral.getOperatorInfo(msg.sender); + uint256 currentUtilizeSDCollateral = sdCollateral.operatorUtilizedSDBalance(msg.sender); + uint256 maxSDUtilizeValue = nonTerminalKeyCount * sdCollateral.convertETHToSD(maxETHWorthOfSDPerValidator); + if (currentUtilizeSDCollateral + utilizeAmount > maxSDUtilizeValue) { + revert SDUtilizeLimitReached(); + } + accrueFee(); + _utilize(msg.sender, utilizeAmount); + } + + /** + * @notice utilize SD from the protocol to add it as collateral for `operator` to run validators + * @dev only `NODE REGISTRY` contract call call + * @param operator address of an ETHx operator + * @param utilizeAmount The amount of the SD token to utilize + * @param nonTerminalKeyCount count of operator's non terminal keys + * + */ //TODO can we remove this ROLE and use something else? function utilizeWhileAddingKeys( address operator, @@ -163,7 +291,7 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr * utilizeIndexNew = simpleFeeFactor * utilizeIndex + utilizeIndex */ - uint256 simpleFeeFactor = utilizationRate * blockDelta; + uint256 simpleFeeFactor = utilizationRatePerBlock * blockDelta; uint256 feeAccumulated = (simpleFeeFactor * totalUtilizedSD) / DECIMAL; totalUtilizedSD = feeAccumulated + totalUtilizedSD; totalProtocolFee = (protocolFeeFactor * feeAccumulated) / DECIMAL + totalProtocolFee; @@ -179,9 +307,9 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr * @param account The address whose balance should be calculated after updating utilizeIndex * @return The calculated balance */ - function utilizeBalanceCurrent(address account) external returns (uint256) { + function utilizerBalanceCurrent(address account) external returns (uint256) { accrueFee(); - return _utilizeBalanceStoredInternal(account); + return _utilizerBalanceStoredInternal(account); } /** @@ -189,8 +317,8 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr * @param account The address whose balance should be calculated * @return The calculated balance */ - function utilizeBalanceStored(address account) external view returns (uint256) { - return _utilizeBalanceStoredInternal(account); + function utilizerBalanceStored(address account) external view returns (uint256) { + return _utilizerBalanceStoredInternal(account); } /// @notice Calculates the utilization of the utility pool @@ -200,13 +328,13 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr return 0; } - return (totalUtilizedSD * DECIMAL) / (getPoolSDBalance() + totalUtilizedSD - totalProtocolFee); + return (totalUtilizedSD * DECIMAL) / (getPoolAvailableSDBalance() + totalUtilizedSD - totalProtocolFee); } /// @notice Calculates the current delegation rate per block function getDelegationRate() external view returns (uint256) { uint256 oneMinusProtocolFeeFactor = DECIMAL - protocolFeeFactor; - uint256 rateToPool = (utilizationRate * oneMinusProtocolFeeFactor) / DECIMAL; + uint256 rateToPool = (utilizationRatePerBlock * oneMinusProtocolFeeFactor) / DECIMAL; return (poolUtilization() * rateToPool) / DECIMAL; } @@ -243,32 +371,28 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr if (!IERC20(staderConfig.getStaderToken()).transferFrom(msg.sender, address(this), sdAmount)) { revert SDTransferFailed(); } - uint256 sdXToMint = (sdAmount * DECIMAL) / exchangeRate; - SDX(staderConfig.getSDxToken()).mint(msg.sender, sdXToMint); + uint256 cTokenToMint = (sdAmount * DECIMAL) / exchangeRate; + delegatorCTokenBalance[msg.sender] += cTokenToMint; + cTokenTotalSupply += cTokenToMint; - emit Delegated(msg.sender, sdAmount, sdXToMint); + emit Delegated(msg.sender, sdAmount, cTokenToMint); } - /** - * @dev Assumes fee has already been accrued up to the current block - * @param sdXAmount The amount of the SDx token to to withdraw - */ - function _redeem(uint256 sdXAmount) internal { - uint256 exchangeRate = _exchangeRateStoredInternal(); - uint256 redeemAmount = (exchangeRate * sdXAmount) / DECIMAL; - - /* Verify `accrualBlockNumber` block number equals current block number */ - if (accrualBlockNumber != block.number) { - revert AccrualBlockNumberNotLatest(); - } - if (getPoolSDBalance() < redeemAmount) { - revert InsufficientPoolBalance(); - } - SDX(staderConfig.getSDxToken()).burnFrom(msg.sender, sdXAmount); - if (!IERC20(staderConfig.getStaderToken()).transferFrom(address(this), msg.sender, redeemAmount)) { - revert SDTransferFailed(); + function _requestWithdraw(uint256 _sdAmountToWithdraw, uint256 cTokenToBurn) internal returns (uint256) { + if (requestIdsByDelegatorAddress[msg.sender].length + 1 > maxNonRedeemedDelegatorRequestCount) { + revert MaxLimitOnWithdrawRequestCountReached(); } - emit Redeemed(msg.sender, redeemAmount, sdXAmount); + sdRequestedForWithdraw += _sdAmountToWithdraw; + delegatorWithdrawRequests[nextRequestId] = DelegatorWithdrawInfo( + msg.sender, + cTokenToBurn, + _sdAmountToWithdraw, + block.number + ); + requestIdsByDelegatorAddress[msg.sender].push(nextRequestId); + emit WithdrawRequestReceived(msg.sender, nextRequestId, _sdAmountToWithdraw); + nextRequestId++; + return nextRequestId - 1; } function _utilize(address utilizer, uint256 utilizeAmount) internal { @@ -276,10 +400,10 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr if (accrualBlockNumber != block.number) { revert AccrualBlockNumberNotLatest(); } - if (getPoolSDBalance() < utilizeAmount) { + if (getPoolAvailableSDBalance() < utilizeAmount) { revert InsufficientPoolBalance(); } - uint256 accountUtilizePrev = _utilizeBalanceStoredInternal(utilizer); + uint256 accountUtilizePrev = _utilizerBalanceStoredInternal(utilizer); utilizerData[utilizer].principal = accountUtilizePrev + utilizeAmount; utilizerData[utilizer].utilizeIndex = utilizeIndex; @@ -295,7 +419,7 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr } /* We fetch the amount the utilizer owes, with accumulated fee */ - uint256 accountUtilizePrev = _utilizeBalanceStoredInternal(utilizer); + uint256 accountUtilizePrev = _utilizerBalanceStoredInternal(utilizer); uint256 repayAmountFinal = (repayAmount == type(uint256).max || repayAmount > accountUtilizePrev) ? accountUtilizePrev @@ -328,7 +452,7 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr * @param account The address whose balance should be calculated * @return (calculated balance) */ - function _utilizeBalanceStoredInternal(address account) internal view returns (uint256) { + function _utilizerBalanceStoredInternal(address account) internal view returns (uint256) { /* Get utilizeBalance and utilizeIndex */ UtilizerStruct storage utilizeSnapshot = utilizerData[account]; @@ -352,7 +476,9 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr * @return calculated exchange rate scaled by 1e18 */ function _exchangeRateStoredInternal() internal view virtual returns (uint256) { - uint256 _totalSupply = SDX(staderConfig.getSDxToken()).totalSupply(); + //fetch totalSupply here + uint256 _totalSupply; + // uint256 _totalSupply = SDX(staderConfig.getSDxToken()).totalSupply(); if (_totalSupply == 0) { /* * If there are no tokens minted: @@ -364,14 +490,34 @@ contract SDUtilityPool is ISDUtilityPool, AccessControlUpgradeable, PausableUpgr * Otherwise: * exchangeRate = (totalCash + totalUtilizedSD - totalFee) / totalSupply */ - uint256 poolBalancePlusUtilizedSDMinusReserves = getPoolSDBalance() + totalUtilizedSD - totalProtocolFee; + uint256 poolBalancePlusUtilizedSDMinusReserves = getPoolAvailableSDBalance() + + totalUtilizedSD - + totalProtocolFee; uint256 exchangeRate = (poolBalancePlusUtilizedSDMinusReserves * DECIMAL) / _totalSupply; return exchangeRate; } } - function getPoolSDBalance() public view returns (uint256) { - return SDX(staderConfig.getSDxToken()).balanceOf(address(this)); + // delete entry from delegatorWithdrawRequests mapping and in requestIdsByDelegatorAddress mapping + function _deleteRequestId(uint256 _requestId) internal { + delete (delegatorWithdrawRequests[_requestId]); + uint256 userRequestCount = requestIdsByDelegatorAddress[msg.sender].length; + uint256[] storage requestIds = requestIdsByDelegatorAddress[msg.sender]; + for (uint256 i; i < userRequestCount; ) { + if (_requestId == requestIds[i]) { + requestIds[i] = requestIds[userRequestCount - 1]; + requestIds.pop(); + return; + } + unchecked { + ++i; + } + } + revert CannotFindRequestId(); + } + + function getPoolAvailableSDBalance() public view returns (uint256) { + return IERC20(staderConfig.getStaderToken()).balanceOf(address(this)) - sdReservedForClaim; } } diff --git a/contracts/SDX.sol b/contracts/SDX.sol deleted file mode 100644 index d646d588..00000000 --- a/contracts/SDX.sol +++ /dev/null @@ -1,86 +0,0 @@ -// SPDX-License-Identifier: GPL-3.0-or-later -pragma solidity 0.8.16; - -import '@openzeppelin/contracts-upgradeable/token/ERC20/ERC20Upgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/access/AccessControlUpgradeable.sol'; -import '@openzeppelin/contracts-upgradeable/security/PausableUpgradeable.sol'; - -import './interfaces/IStaderConfig.sol'; -import './library/UtilLib.sol'; - -/** - * @title SDx token Contract - * @author Stader Labs - * @notice The ERC20 contract for the SDx token - */ - -contract SDX is Initializable, ERC20Upgradeable, PausableUpgradeable, AccessControlUpgradeable { - event UpdatedStaderConfig(address indexed _staderConfig); - - IStaderConfig public staderConfig; - - /// @custom:oz-upgrades-unsafe-allow constructor - constructor() { - _disableInitializers(); - } - - function initialize(address _admin, address _staderConfig) external initializer { - UtilLib.checkNonZeroAddress(_admin); - UtilLib.checkNonZeroAddress(_staderConfig); - - __ERC20_init('Interest bearing SD token', 'SDx'); - __Pausable_init(); - __AccessControl_init(); - - staderConfig = IStaderConfig(_staderConfig); - _grantRole(DEFAULT_ADMIN_ROLE, _admin); - - emit UpdatedStaderConfig(_staderConfig); - } - - /** - * @notice Mints SDx when called by an authorized caller - * @param to the account to mint to - * @param amount the amount of SDx to mint - */ - function mint(address to, uint256 amount) external whenNotPaused { - UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.SD_UTILITY_POOL()); - - _mint(to, amount); - } - - /** - * @notice Burns SDx when called by an authorized caller - * @param account the account to burn from - * @param amount the amount of SDx to burn - */ - function burnFrom(address account, uint256 amount) external whenNotPaused { - UtilLib.onlyStaderContract(msg.sender, staderConfig, staderConfig.SD_UTILITY_POOL()); - - _burn(account, amount); - } - - /** - * @dev Triggers stopped state. - * Contract must not be paused. - */ - function pause() external { - UtilLib.onlyManagerRole(msg.sender, staderConfig); - - _pause(); - } - - /** - * @dev Returns to normal state. - * Contract must be paused - */ - function unpause() external onlyRole(DEFAULT_ADMIN_ROLE) { - _unpause(); - } - - function updateStaderConfig(address _staderConfig) external onlyRole(DEFAULT_ADMIN_ROLE) { - UtilLib.checkNonZeroAddress(_staderConfig); - staderConfig = IStaderConfig(_staderConfig); - emit UpdatedStaderConfig(_staderConfig); - } -} diff --git a/contracts/StaderConfig.sol b/contracts/StaderConfig.sol index e93c244e..304f2212 100644 --- a/contracts/StaderConfig.sol +++ b/contracts/StaderConfig.sol @@ -77,7 +77,6 @@ contract StaderConfig is IStaderConfig, AccessControlUpgradeable { mapping(bytes32 => address) private contractsMap; mapping(bytes32 => address) private tokensMap; - bytes32 public constant override SDx = keccak256('SDx'); bytes32 public constant override SD_UTILITY_POOL = keccak256('SD_UTILITY_POOL'); bytes32 public constant override SD_INCENTIVE_CONTROLLER = keccak256('SD_INCENTIVE_CONTROLLER'); @@ -296,10 +295,6 @@ contract StaderConfig is IStaderConfig, AccessControlUpgradeable { setToken(ETHx, _ethX); } - function updateSDxToken(address _sdX) external onlyRole(DEFAULT_ADMIN_ROLE) { - setToken(SDx, _sdX); - } - function updateSDUtilityPool(address _utilityPool) external onlyRole(DEFAULT_ADMIN_ROLE) { setContract(SD_UTILITY_POOL, _utilityPool); } @@ -491,10 +486,6 @@ contract StaderConfig is IStaderConfig, AccessControlUpgradeable { return tokensMap[ETHx]; } - function getSDxToken() external view override returns (address) { - return tokensMap[SDx]; - } - // SETTER HELPERS function setConstant(bytes32 key, uint256 val) internal { if (constantsMap[key] == val) { diff --git a/contracts/interfaces/ISDUtilityPool.sol b/contracts/interfaces/ISDUtilityPool.sol index 4c2a7bc7..bf6e45c1 100644 --- a/contracts/interfaces/ISDUtilityPool.sol +++ b/contracts/interfaces/ISDUtilityPool.sol @@ -3,24 +3,40 @@ pragma solidity 0.8.16; interface ISDUtilityPool { error SDTransferFailed(); + error CannotFindRequestId(); error SDUtilizeLimitReached(); + error InvalidAmountOfWithdraw(); error InsufficientPoolBalance(); error AccrualBlockNumberNotLatest(); + error CallerNotAuthorizedToRedeem(); + error MaxLimitOnWithdrawRequestCountReached(); + error requestIdNotFinalized(uint256 requestId); event UpdatedStaderConfig(address indexed _staderConfig); + event RequestRedeemed(address caller, uint256 sdToTransfer); event Delegated(address indexed delegator, uint256 sdAmount, uint256 sdXToMint); event Redeemed(address indexed delegator, uint256 sdAmount, uint256 sdXAmount); event Repaid(address indexed utilizer, uint256 repayAmount); event AccruedFees(uint256 feeAccumulated, uint256 totalProtocolFee, uint256 totalUtilizedSD); + event WithdrawRequestReceived(address caller, uint256 nextRequestId, uint256 sdAmountToWithdraw); + + function cTokenTotalSupply() external view returns (uint256); + + function delegatorCTokenBalance(address) external view returns (uint256); + function delegate(uint256 sdAmount) external; - // function requestWithdraw(uint256 sdAmount) external return (uint); + function requestWithdraw(uint256 cTokenAmount) external returns (uint256); + + function requestWithdrawWithSDAmount(uint256 sdAmount) external returns (uint256); + + function finalizeDelegatorWithdrawalRequest() external; - // function claim(uint256 requestId) external; + function claim(uint256 requestId) external; - function redeem(uint256 sdXAmount) external; + function utilize(uint256 utilizeAmount) external; function utilizeWhileAddingKeys( address operator, @@ -34,9 +50,9 @@ interface ISDUtilityPool { function accrueFee() external; - function utilizeBalanceCurrent(address account) external returns (uint256); + function utilizerBalanceCurrent(address account) external returns (uint256); - function utilizeBalanceStored(address account) external view returns (uint256); + function utilizerBalanceStored(address account) external view returns (uint256); function poolUtilization() external view returns (uint256); @@ -46,5 +62,5 @@ interface ISDUtilityPool { function exchangeRateStored() external view returns (uint256); - function getPoolSDBalance() external view returns (uint256); + function getPoolAvailableSDBalance() external view returns (uint256); } diff --git a/contracts/interfaces/IStaderConfig.sol b/contracts/interfaces/IStaderConfig.sol index fd0060f4..f8f9854a 100644 --- a/contracts/interfaces/IStaderConfig.sol +++ b/contracts/interfaces/IStaderConfig.sol @@ -59,7 +59,6 @@ interface IStaderConfig { function VALIDATOR_WITHDRAWAL_VAULT_IMPLEMENTATION() external view returns (bytes32); //SD Utility Pool - function SDx() external view returns (bytes32); function SD_UTILITY_POOL() external view returns (bytes32); @@ -166,8 +165,6 @@ interface IStaderConfig { function getETHxToken() external view returns (address); - function getSDxToken() external view returns (address); - //checks roles and stader contracts function onlyStaderContract(address _addr, bytes32 _contractName) external view returns (bool); diff --git a/contracts/interfaces/SDCollateral/ISDCollateral.sol b/contracts/interfaces/SDCollateral/ISDCollateral.sol index c7e3a352..96d8240d 100644 --- a/contracts/interfaces/SDCollateral/ISDCollateral.sol +++ b/contracts/interfaces/SDCollateral/ISDCollateral.sol @@ -80,4 +80,13 @@ interface ISDCollateral { function convertSDToETH(uint256 _sdAmount) external view returns (uint256); function convertETHToSD(uint256 _ethAmount) external view returns (uint256); + + function getOperatorInfo(address _operator) + external + view + returns ( + uint8 _poolId, + uint256 _operatorId, + uint256 _validatorCount + ); }