Skip to content

Commit

Permalink
Merge pull request #206 from lidofinance/fix/empty-unsteth-unlock
Browse files Browse the repository at this point in the history
Fix/empty unsteth unlock
  • Loading branch information
bulbozaur authored Nov 20, 2024
2 parents 0eb8194 + 1f5b05b commit ce17a31
Show file tree
Hide file tree
Showing 7 changed files with 1,637 additions and 35 deletions.
3 changes: 3 additions & 0 deletions contracts/Escrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -251,6 +251,9 @@ contract Escrow is IEscrow {
/// that were previously locked by the vetoer.
/// @param unstETHIds An array of ids representing the unstETH NFTs to be unlocked.
function unlockUnstETH(uint256[] memory unstETHIds) external {
if (unstETHIds.length == 0) {
revert EmptyUnstETHIds();
}
DUAL_GOVERNANCE.activateNextState();
_escrowState.checkSignallingEscrow();
_accounting.checkMinAssetsLockDurationPassed(msg.sender, _escrowState.minAssetsLockDuration);
Expand Down
2 changes: 0 additions & 2 deletions contracts/ImmutableDualGovernanceConfigProvider.sol
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ contract ImmutableDualGovernanceConfigProvider is IDualGovernanceConfigProvider
Duration public immutable RAGE_QUIT_ETH_WITHDRAWALS_DELAY_GROWTH;

constructor(DualGovernanceConfig.Context memory dualGovernanceConfig) {
dualGovernanceConfig.validate();

FIRST_SEAL_RAGE_QUIT_SUPPORT = dualGovernanceConfig.firstSealRageQuitSupport;
SECOND_SEAL_RAGE_QUIT_SUPPORT = dualGovernanceConfig.secondSealRageQuitSupport;

Expand Down
89 changes: 57 additions & 32 deletions test/mocks/WithdrawalQueueMock.sol
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

// import {ERC721} from "@openzeppelin/contracts/token/ERC721/ERC721.sol"; /*, ERC721("test", "test")*/
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import {IWithdrawalQueue, WithdrawalRequestStatus} from "contracts/interfaces/IWithdrawalQueue.sol";
import {ETHValues, sendTo} from "contracts/types/ETHValue.sol";

/* solhint-disable no-unused-vars,custom-errors */
contract WithdrawalQueueMock is IWithdrawalQueue {
address private _stETH;
uint256 private _lastRequestId;
uint256 private _lastFinalizedRequestId;
uint256 private _minStETHWithdrawalAmount;
uint256 private _maxStETHWithdrawalAmount;
uint256 private _claimableAmount;
uint256 private _requestWithdrawalsTransferAmount;
uint256[] private _requestWithdrawalsResult;

constructor() {}
constructor(address stETH) {
_stETH = stETH;
}

function MIN_STETH_WITHDRAWAL_AMOUNT() external view returns (uint256) {
return _minStETHWithdrawalAmount;
Expand All @@ -22,8 +28,14 @@ contract WithdrawalQueueMock is IWithdrawalQueue {
return _maxStETHWithdrawalAmount;
}

function claimWithdrawals(uint256[] calldata requestIds, uint256[] calldata hints) external {
revert("Not Implemented");
function claimWithdrawals(uint256[] calldata, /* requestIds */ uint256[] calldata /* hints */ ) external {
if (_claimableAmount == 0) {
return;
}

sendTo(ETHValues.from(_claimableAmount), payable(msg.sender));

setClaimableAmount(0);
}

function getLastRequestId() external view returns (uint256) {
Expand All @@ -34,82 +46,87 @@ contract WithdrawalQueueMock is IWithdrawalQueue {
return _lastFinalizedRequestId;
}

function getWithdrawalStatus(uint256[] calldata _requestIds)
function getWithdrawalStatus(uint256[] calldata /* _requestIds */ )
external
view
returns (WithdrawalRequestStatus[] memory statuses)
pure
returns (WithdrawalRequestStatus[] memory /* statuses */ )
{
revert("Not Implemented");
}

/// @notice Returns amount of ether available for claim for each provided request id
/// @param _requestIds array of request ids
/// @param _hints checkpoint hints. can be found with `findCheckpointHints(_requestIds, 1, getLastCheckpointIndex())`
/// @return claimableEthValues amount of claimable ether for each request, amount is equal to 0 if request
/// is not finalized or already claimed
function getClaimableEther(
uint256[] calldata _requestIds,
uint256[] calldata _hints
) external view returns (uint256[] memory claimableEthValues) {
uint256[] calldata, /* _requestIds */
uint256[] calldata /* _hints */
) external pure returns (uint256[] memory /* claimableEthValues */ ) {
revert("Not Implemented");
}

function findCheckpointHints(
uint256[] calldata _requestIds,
uint256 _firstIndex,
uint256 _lastIndex
) external view returns (uint256[] memory hintIds) {
uint256[] calldata, /* _requestIds */
uint256, /* _firstIndex */
uint256 /* _lastIndex */
) external pure returns (uint256[] memory /* hintIds */ ) {
revert("Not Implemented");
}

function getLastCheckpointIndex() external view returns (uint256) {
function getLastCheckpointIndex() external pure returns (uint256) {
revert("Not Implemented");
}

function requestWithdrawals(
uint256[] calldata _amounts,
address _owner
uint256[] calldata, /* _amounts */
address /* _owner */
) external returns (uint256[] memory requestIds) {
if (_requestWithdrawalsTransferAmount > 0) {
IERC20(_stETH).transferFrom(msg.sender, address(this), _requestWithdrawalsTransferAmount);
setRequestWithdrawalsTransferAmount(0);
}

return _requestWithdrawalsResult;
}

function balanceOf(address owner) external view returns (uint256 balance) {
function balanceOf(address /* owner */ ) external pure returns (uint256 /* balance */ ) {
revert("Not Implemented");
}

function ownerOf(uint256 tokenId) external view returns (address owner) {
function ownerOf(uint256 /* tokenId */ ) external pure returns (address /* owner */ ) {
revert("Not Implemented");
}

function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external {
function safeTransferFrom(
address, /* from */
address, /* to */
uint256, /* tokenId */
bytes calldata /* data */
) external pure {
revert("Not Implemented");
}

function safeTransferFrom(address from, address to, uint256 tokenId) external {
function safeTransferFrom(address, /* from */ address, /* to */ uint256 /* tokenId */ ) external pure {
revert("Not Implemented");
}

function transferFrom(address from, address to, uint256 tokenId) external {
function transferFrom(address, /* from */ address, /* to */ uint256 /* tokenId */ ) external pure {
revert("Not Implemented");
}

function approve(address to, uint256 tokenId) external {
function approve(address, /* to */ uint256 /* tokenId */ ) external pure {
revert("Not Implemented");
}

function setApprovalForAll(address operator, bool approved) external {
function setApprovalForAll(address, /* operator */ bool /* approved */ ) external pure {
revert("Not Implemented");
}

function getApproved(uint256 tokenId) external view returns (address operator) {
function getApproved(uint256 /* tokenId */ ) external pure returns (address /* operator */ ) {
revert("Not Implemented");
}

function isApprovedForAll(address owner, address operator) external view returns (bool) {
function isApprovedForAll(address, /* owner */ address /* operator */ ) external pure returns (bool) {
revert("Not Implemented");
}

function supportsInterface(bytes4 interfaceId) external view returns (bool) {
function supportsInterface(bytes4 /* interfaceId */ ) external pure returns (bool) {
revert("Not Implemented");
}

Expand All @@ -132,4 +149,12 @@ contract WithdrawalQueueMock is IWithdrawalQueue {
function setRequestWithdrawalsResult(uint256[] memory requestIds) public {
_requestWithdrawalsResult = requestIds;
}

function setClaimableAmount(uint256 claimableAmount) public {
_claimableAmount = claimableAmount;
}

function setRequestWithdrawalsTransferAmount(uint256 requestWithdrawalsTransferAmount) public {
_requestWithdrawalsTransferAmount = requestWithdrawalsTransferAmount;
}
}
20 changes: 20 additions & 0 deletions test/mocks/WstETHMock.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: MIT
pragma solidity 0.8.26;

import {ERC20Mock} from "@openzeppelin/contracts/mocks/token/ERC20Mock.sol";
import {IWstETH} from "contracts/interfaces/IWstETH.sol";

/* solhint-disable no-unused-vars,custom-errors */
contract WstETHMock is ERC20Mock, IWstETH {
function wrap(uint256 /* stETHAmount */ ) external pure returns (uint256) {
revert("Not Implemented");
}

function unwrap(uint256 /* wstETHAmount */ ) external pure returns (uint256) {
revert("Not Implemented");
}

function getStETHByWstETH(uint256 /* wstethAmount */ ) external pure returns (uint256) {
revert("Not Implemented");
}
}
2 changes: 1 addition & 1 deletion test/unit/DualGovernance.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ contract DualGovernanceUnitTests is UnitTest {
address private vetoer = makeAddr("vetoer");

StETHMock private immutable _STETH_MOCK = new StETHMock();
IWithdrawalQueue private immutable _WITHDRAWAL_QUEUE_MOCK = new WithdrawalQueueMock();
IWithdrawalQueue private immutable _WITHDRAWAL_QUEUE_MOCK = new WithdrawalQueueMock(address(_STETH_MOCK));

// TODO: Replace with mocks
IWstETH private immutable _WSTETH_STUB = IWstETH(makeAddr("WSTETH_STUB"));
Expand Down
Loading

0 comments on commit ce17a31

Please sign in to comment.