Skip to content

Latest commit

 

History

History
50 lines (37 loc) · 1.75 KB

073.md

File metadata and controls

50 lines (37 loc) · 1.75 KB

Fierce Coral Turkey

High

User can frontrun slashing by withdrawing

Description

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 calling claimWithdrawal first.
  • This allows him to quickly claim his withdrawal before the slash occurs.

Recommendation

Prevent users from being able to frontrun slashing by quickly claiming their withdrawal