Fierce Coral Turkey
High
Let’s consider a scenario where Bob is about to be slashed. This would trigger the slash
function:
function slash(uint256 sequencersBitmap) external onlyRollupContract nonReentrant returns (uint256) {
address[] memory sequencers = getStakersFromBitmap(sequencersBitmap);
uint256 valueSum;
for (uint256 i = 0; i < sequencers.length; i++) {
if (withdrawals[sequencers[i]] > 0) {
delete withdrawals[sequencers[i]];
valueSum += stakingValue;
//..Omitted code
If a sequencer
has a pending withdrawal, it will be removed as seen in this line:
delete withdrawals[sequencers[i]];
Users can claim their withdrawal by invoking claimWithdrawal
:
function claimWithdrawal(address receiver) external nonReentrant {
require(withdrawals[_msgSender()] > 0, "withdrawal not exist");
require(withdrawals[_msgSender()] < block.number, "withdrawal locked");
delete withdrawals[_msgSender()];
_cleanStakerStore();
emit Claimed(_msgSender(), receiver);
_transfer(receiver, stakingValue);
}
Based on this logic, a user could execute the following steps:
- Bob is about to be slashed while having a pending withdrawal.
- His withdrawal request would be deleted when
slash
is called. - To avoid this, Bob can frontrun the
slash
function by callingclaimWithdrawal
first. - This allows him to quickly claim his withdrawal before the slash occurs.
Prevent users from being able to frontrun slashing by quickly claiming their withdrawal