Closed sherlock-admin2 closed 9 months ago
1 comment(s) were left on this issue during the judging contest.
_rahul commented:
Invalid: Recipient has authorized escrow to be fully revokable to help recover funds (incase of loss of recipient address etc) during setup. Essentially, owner calls revokeAll() to rescue funds for the recipient. In this context, it’s unlikely that will recipient front-run revokeAll().
0xmystery
medium
Front-Running Vulnerability in revokeAll Function of VestingEscrow Contract
Summary
A potential front-running vulnerability exists in the
revokeAll
function of the VestingEscrow contract. This issue allows a recipient to potentially claim unvested tokens before the owner's revocation transaction is processed, leading to an unexpected depletion of the tokens intended to be revoked.Vulnerability Detail
The
revokeAll
function is designed to allow the contract owner to revoke all tokens (locked and unclaimed) from the contract. However, this function is susceptible to a front-running attack. A malicious or opportunistic recipient can monitor the Ethereum mempool forrevokeAll
transactions and execute aclaim
transaction with a higher gas fee to ensure it is processed first. This action allows the recipient to withdraw the remaining portion of the unclaimed tokens, reducing the amount available for revocation when therevokeAll
transaction is subsequently processed.Impact
It undermines the intended functionality of the
revokeAll
feature and can result in a lesser amount of tokens being revoked than anticipated by the owner. This could impact the contract's financial and operational aspects, particularly in scenarios where precise control over token vesting and revocation is crucial.Code Snippet
https://github.com/sherlock-audit/2024-01-rio-vesting-escrow/blob/main/rio-vesting-escrow/src/VestingEscrow.sol#L176-L189
Tool used
Manual Review
Recommendation
Introducing a
claimRequest
function with a time delay before tokens can actually be claimed is a viable strategy to mitigate the front-running issue in your smart contract. This approach adds a layer of protection by separating the request to claim tokens from the actual transfer of tokens. Here's an overview of how this could work and its implications:Claim Request Function (claimRequest):
Claim Request Function (
claimRequest
):Claim Execution Function (
executeClaim
):claimRequest
, the recipient can call this function to actually transfer the tokens.claimRequest
.This approach minimizes the risk of front-running since the recipient cannot immediately claim the tokens till
(block.timestamp >= claimRequestTimestamps[msg.sender] + claimDelay) == true
.Duplicate of #63