40,000 USDC
View results
Submission Details
Severity: medium
Valid

Possible DOS of `resolveDispute()` by sellers

Summary

resolveDispute() might revert by malicious sellers with the tokens with blocklists.

Vulnerability Details

Some well-known tokens have blocklists.

The seller can make resolveDispute() revert with 1 wei using frontrunning.

function resolveDispute(uint256 buyerAward) external onlyArbiter nonReentrant inState(State.Disputed) {
uint256 tokenBalance = i_tokenContract.balanceOf(address(this));
uint256 totalFee = buyerAward + i_arbiterFee; // Reverts on overflow
if (totalFee > tokenBalance) {
revert Escrow__TotalFeeExceedsBalance(tokenBalance, totalFee);
}
s_state = State.Resolved;
emit Resolved(i_buyer, i_seller);
if (buyerAward > 0) {
i_tokenContract.safeTransfer(i_buyer, buyerAward);
}
if (i_arbiterFee > 0) {
i_tokenContract.safeTransfer(i_arbiter, i_arbiterFee);
}
tokenBalance = i_tokenContract.balanceOf(address(this));
if (tokenBalance > 0) {
i_tokenContract.safeTransfer(i_seller, tokenBalance); //@audit possible DOS
}
}
  1. Create an escrow with the token with a blacklist

  2. The seller disputes right away or waits until the buyer disputes without doing his task.

  3. When the arbiter is going to call resolveDispute() for the buyer’s preference, the seller transfers 1 wei to the escrow by frontrunning

  4. Then the token balance for the seller will be positive even if the arbiter was going to transfer all funds to the buyer, and the seller can DOS by reverting the transfer.

Impact

The buyers wouldn't receive back their funds after disputes.

Tools Used

Manual Review

Recommendations

We can modify resolveDispute() to accept type(uint256).max and transfer all funds to the buyer at that time.

Then the seller won't have an opportunity to DOS because there is no transfer for him.

function resolveDispute(uint256 buyerAward) external onlyArbiter nonReentrant inState(State.Disputed) {
uint256 tokenBalance = i_tokenContract.balanceOf(address(this));
//check buyerAward
if (buyerAward == type(uint256).max) {
buyerAward = tokenBalance - i_arbiterFee;
}
uint256 totalFee = buyerAward + i_arbiterFee; // Reverts on overflow
if (totalFee > tokenBalance) {
revert Escrow__TotalFeeExceedsBalance(tokenBalance, totalFee);
}
s_state = State.Resolved;
emit Resolved(i_buyer, i_seller);
if (buyerAward > 0) {
i_tokenContract.safeTransfer(i_buyer, buyerAward);
}
if (i_arbiterFee > 0) {
i_tokenContract.safeTransfer(i_arbiter, i_arbiterFee);
}
tokenBalance = i_tokenContract.balanceOf(address(this));
if (tokenBalance > 0) {
i_tokenContract.safeTransfer(i_seller, tokenBalance);
}
}

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.