Skip to content

Commit

Permalink
claim user requests separately
Browse files Browse the repository at this point in the history
  • Loading branch information
bulbozaur committed Feb 14, 2024
1 parent 3242513 commit c5f72cc
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 32 deletions.
63 changes: 52 additions & 11 deletions contracts/Escrow.sol
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ contract Escrow {
error FinalizedRequest(uint256);
error RequestNotFound(uint256 id);
error SenderIsNotAllowed();
error RequestIsNotFromBatch(uint256 id);
error RequestFromBatch(uint256 id);

event RageQuitAccumulationStarted();
event RageQuitStarted();
Expand All @@ -95,13 +97,24 @@ contract Escrow {
uint256 wstEthInEthShares;
uint256 wqRequestsBalance;
uint256 finalizedWqRequestsBalance;
// uint256[] wqRequestIds;
uint256 eth;
}

struct WithdrawalRequest {
uint256 stEthInEthShares;
uint256 wstEthInEthShares;
uint256 wqRequestsBalance;
uint256 finalizedWqRequestsBalance;
}

struct Balance {
uint256 stEth;
uint256 wstEth;
uint256 wqRequestsBalance;
uint256 finalizedWqRequestsBalance;
// WithdrawalReqsuest[] wqRequests;
uint256 eth;
}

Configuration internal immutable CONFIG;
Expand All @@ -117,6 +130,7 @@ contract Escrow {
uint256 internal _totalWstEthInEthLocked;
uint256 internal _totalWithdrawalNftsAmountLocked;
uint256 internal _totalFinalizedWithdrawalNftsAmountLocked;
uint256 internal _totalClaimedEthLocked;

uint256 internal _totalEscrowShares;
uint256 internal _claimedWQRequestsAmount;
Expand Down Expand Up @@ -157,6 +171,7 @@ contract Escrow {
balance.wstEth = IStETH(ST_ETH).getSharesByPooledEth(_getETHByShares(state.wstEthInEthShares));
balance.wqRequestsBalance = state.wqRequestsBalance;
balance.finalizedWqRequestsBalance = state.finalizedWqRequestsBalance;
balance.eth = state.eth;
}

function lockStEth(uint256 amount) external {
Expand Down Expand Up @@ -308,13 +323,17 @@ contract Escrow {
address sender = msg.sender;
HolderState memory state = _balances[sender];

uint256 ethToClaim =
(state.stEthInEthShares + state.wqRequestsBalance) * _rageQuitAmountTotal / _totalEscrowShares;
uint256 ethToClaim = _getETHByShares(state.stEthInEthShares);
ethToClaim += _getETHByShares(state.wstEthInEthShares);
ethToClaim += _balances[sender].eth;

_balances[sender].stEthInEthShares = 0;
_balances[sender].wstEthInEthShares = 0;
_balances[sender].eth = 0;

payable(sender).transfer(ethToClaim);
if (ethToClaim > 0) {
payable(sender).transfer(ethToClaim);
}
}

///
Expand Down Expand Up @@ -381,7 +400,8 @@ contract Escrow {
_totalStEthInEthLocked + _totalWstEthInEthLocked + _totalWithdrawalNftsAmountLocked;
rageQuitSupport = (totalRageQuitStEthLocked * 10 ** 18) / stEthTotalSupply;

uint256 totalStakedEthLocked = totalRageQuitStEthLocked + _totalFinalizedWithdrawalNftsAmountLocked;
uint256 totalStakedEthLocked =
totalRageQuitStEthLocked + _totalFinalizedWithdrawalNftsAmountLocked + _totalClaimedEthLocked;
totalSupport = (totalStakedEthLocked * 10 ** 18) / stEthTotalSupply;
}

Expand Down Expand Up @@ -490,15 +510,36 @@ contract Escrow {
for (uint256 i = 0; i < requestIds.length; ++i) {
uint256 id = requestIds[i];
address owner = _wqRequests[id].owner;
if (owner == address(this)) {
_claimedWQRequestsAmount += wqRequestStatuses[i].amountOfStETH;
} else {
_balances[owner].finalizedWqRequestsBalance += wqRequestStatuses[i].amountOfStETH;
_balances[owner].wqRequestsBalance -= _wqRequests[id].amountOfStETH;
if (owner != address(this)) {
revert RequestIsNotFromBatch(id);
}
_claimedWQRequestsAmount += wqRequestStatuses[i].amountOfStETH;
}
}

_totalFinalizedWithdrawalNftsAmountLocked += wqRequestStatuses[i].amountOfStETH;
_totalWithdrawalNftsAmountLocked -= _wqRequests[id].amountOfStETH;
function claimWithdrawalRequests(uint256[] calldata requestIds, uint256[] calldata hints) external {
IWithdrawalQueue(WITHDRAWAL_QUEUE).claimWithdrawals(requestIds, hints);

WithdrawalRequestStatus[] memory wqRequestStatuses =
IWithdrawalQueue(WITHDRAWAL_QUEUE).getWithdrawalStatus(requestIds);

for (uint256 i = 0; i < requestIds.length; ++i) {
uint256 id = requestIds[i];
WithdrawalRequestStatus memory request = _wqRequests[id];
address owner = request.owner;
if (owner == address(this) || owner == address(0)) {
revert RequestFromBatch(id);
}

if (request.isFinalized) {
_balances[owner].finalizedWqRequestsBalance -= request.amountOfStETH;
_totalFinalizedWithdrawalNftsAmountLocked -= request.amountOfStETH;
} else {
_balances[owner].wqRequestsBalance -= request.amountOfStETH;
_totalWithdrawalNftsAmountLocked -= request.amountOfStETH;
}
_balances[owner].eth += wqRequestStatuses[i].amountOfStETH;
_totalClaimedEthLocked += wqRequestStatuses[i].amountOfStETH;
}
}

Expand Down
77 changes: 56 additions & 21 deletions test/scenario/escrow.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,16 +32,17 @@ contract TestHelpers is DualGovernanceSetup {
);
}

function setLastFinalizedId(uint256 newLastFinalizedId) public {
bytes32 LAST_FINALIZED_REQUEST_ID_POSITION = 0x992f2e0c24ce59a21f2dab8bba13b25c2f872129df7f4d45372155e717db0c48; // keccak256("lido.WithdrawalQueue.lastFinalizedRequestId");

uint256 currentLastFinalizedId = uint256(vm.load(WITHDRAWAL_QUEUE, LAST_FINALIZED_REQUEST_ID_POSITION));

assertEq(newLastFinalizedId > currentLastFinalizedId, true);
vm.store(WITHDRAWAL_QUEUE, LAST_FINALIZED_REQUEST_ID_POSITION, bytes32(newLastFinalizedId));
function finalizeWQ() public {
uint256 lastRequestId = IWithdrawalQueue(WITHDRAWAL_QUEUE).getLastRequestId();
finalizeWQ(lastRequestId);
}

function updateLockedEtherAmount() public {
function finalizeWQ(uint256 id) public {
uint256 finalizationShareRate = IStEth(ST_ETH).getPooledEthByShares(1e27) + 1e9; // TODO check finalization rate
address lido = 0xae7ab96520DE3A18E5e111B5EaAb095312D7fE84;
vm.prank(lido);
IWithdrawalQueue(WITHDRAWAL_QUEUE).finalize(id, finalizationShareRate);

bytes32 LOCKED_ETHER_AMOUNT_POSITION = 0x0e27eaa2e71c8572ab988fef0b54cd45bbd1740de1e22343fb6cda7536edc12f; // keccak256("lido.WithdrawalQueue.lockedEtherAmount");

vm.store(WITHDRAWAL_QUEUE, LOCKED_ETHER_AMOUNT_POSITION, bytes32(address(WITHDRAWAL_QUEUE).balance));
Expand Down Expand Up @@ -207,15 +208,14 @@ contract EscrowHappyPath is TestHelpers {
amounts[i] = 1e18;
}

vm.startPrank(stEthHolder1);
vm.prank(stEthHolder1);
uint256[] memory ids = IWithdrawalQueue(WITHDRAWAL_QUEUE).requestWithdrawals(amounts, stEthHolder1);

setLastFinalizedId(ids[1]);
finalizeWQ();

vm.prank(stEthHolder1);
vm.expectRevert();
escrow.lockWithdrawalNFT(ids);

vm.stopPrank();
}

function test_check_finalization() public {
Expand All @@ -233,7 +233,7 @@ contract EscrowHappyPath is TestHelpers {
assertEq(balance.wqRequestsBalance, 2 * 1e18);
assertEq(balance.finalizedWqRequestsBalance, 0);

setLastFinalizedId(ids[0]);
finalizeWQ(ids[0]);
escrow.checkForFinalization(ids);

balance = escrow.balanceOf(stEthHolder1);
Expand Down Expand Up @@ -262,7 +262,7 @@ contract EscrowHappyPath is TestHelpers {
assertEq(totalSupport, 4 * 1e18 * 1e18 / totalSupply);
assertEq(rageQuitSupport, 4 * 1e18 * 1e18 / totalSupply);

setLastFinalizedId(ids[0]);
finalizeWQ(ids[0]);
escrow.checkForFinalization(ids);

balance = escrow.balanceOf(stEthHolder1);
Expand Down Expand Up @@ -305,15 +305,16 @@ contract EscrowHappyPath is TestHelpers {
assertEq(IWithdrawalQueue(WITHDRAWAL_QUEUE).balanceOf(address(escrow)), 50);
assertEq(escrow.isRageQuitFinalized(), false);

setLastFinalizedId(IWithdrawalQueue(WITHDRAWAL_QUEUE).getLastRequestId());
vm.deal(WITHDRAWAL_QUEUE, 1000 * requestAmount);
finalizeWQ();

uint256[] memory hints = IWithdrawalQueue(WITHDRAWAL_QUEUE).findCheckpointHints(
ids,
IWithdrawalQueue(WITHDRAWAL_QUEUE).getLastCheckpointIndex() - 2,
IWithdrawalQueue(WITHDRAWAL_QUEUE).getLastCheckpointIndex()
);

escrow.claimNextETHBatch(ids, hints);
escrow.claimWithdrawalRequests(ids, hints);

assertEq(escrow.isRageQuitFinalized(), true);

Expand All @@ -332,9 +333,6 @@ contract EscrowHappyPath is TestHelpers {
IWithdrawalQueue(WITHDRAWAL_QUEUE).getLastCheckpointIndex()
);

vm.deal(WITHDRAWAL_QUEUE, 100 * requestAmount);
updateLockedEtherAmount();

vm.expectRevert();
vm.prank(stEthHolder1);
escrow.claimETH();
Expand All @@ -345,6 +343,39 @@ contract EscrowHappyPath is TestHelpers {
escrow.claimETH();
}

function test_wq_requests_only_happy_path() public {
uint256 requestAmount = 10 * 1e18;
uint256 requestsCount = 10;
uint256[] memory amounts = new uint256[](requestsCount);
for (uint256 i = 0; i < requestsCount; ++i) {
amounts[i] = requestAmount;
}

vm.prank(stEthHolder1);
uint256[] memory ids = IWithdrawalQueue(WITHDRAWAL_QUEUE).requestWithdrawals(amounts, stEthHolder1);

lockAssets(stEthHolder1, 0, 0, ids);

vm.prank(address(govState));
escrow.startRageQuit();

vm.deal(WITHDRAWAL_QUEUE, 100 * requestAmount);
finalizeWQ();

uint256[] memory hints = IWithdrawalQueue(WITHDRAWAL_QUEUE).findCheckpointHints(
ids,
IWithdrawalQueue(WITHDRAWAL_QUEUE).getLastCheckpointIndex() - 2,
IWithdrawalQueue(WITHDRAWAL_QUEUE).getLastCheckpointIndex()
);

escrow.claimWithdrawalRequests(ids, hints);

assertEq(escrow.isRageQuitFinalized(), true);

vm.prank(stEthHolder1);
escrow.claimETH();
}

function lockAssets(
address owner,
uint256 stEthAmountToLock,
Expand Down Expand Up @@ -382,9 +413,11 @@ contract EscrowHappyPath is TestHelpers {
balanceBefore.stEth + stEthAmountToLock,
balanceBefore.wstEth + wstEthAmountToLock,
balanceBefore.wqRequestsBalance + wqRequestsAmount,
balanceBefore.finalizedWqRequestsBalance
balanceBefore.finalizedWqRequestsBalance,
0
)
);
// new uint256[](0)

assertApproxEqAbs(IERC20(ST_ETH).balanceOf(owner), stEthBalanceBefore - stEthAmountToLock, 3);
assertEq(IERC20(WST_ETH).balanceOf(owner), wstEthBalanceBefore - wstEthAmountToLock);
Expand Down Expand Up @@ -435,9 +468,11 @@ contract EscrowHappyPath is TestHelpers {
unlockStEth ? 0 : balanceBefore.stEth,
unlockWstEth ? 0 : balanceBefore.wstEth,
balanceBefore.wqRequestsBalance - wqRequestsAmount,
balanceBefore.finalizedWqRequestsBalance
balanceBefore.finalizedWqRequestsBalance,
0
)
);
// new uint256[](0)

uint256 expectedStEthAmount = uint256(int256(balanceBefore.stEth) * (10000 + rebaseBP) / 10000);
uint256 expectedWstEthAmount = uint256(int256(balanceBefore.wstEth) * (10000 + rebaseBP) / 10000);
Expand Down
3 changes: 3 additions & 0 deletions test/utils/interfaces.sol
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,7 @@ interface IWithdrawalQueue {
uint256 _lastIndex
) external view returns (uint256[] memory hintIds);
function getLastCheckpointIndex() external view returns (uint256);
function claimWithdrawals(uint256[] calldata requestIds, uint256[] calldata hints) external;
function getLastFinalizedRequestId() external view returns (uint256);
function finalize(uint256 _lastRequestIdToBeFinalized, uint256 _maxShareRate) external payable;
}

0 comments on commit c5f72cc

Please sign in to comment.