Summary
confirmReceipt() or resolveDispute will release amount owed to seller,buyer,arbiter.
If any of the transfer fails, e.g USDC blacklisting, a whole transaction will revert.
Vulnerability Details
function confirmReceipt() external onlyBuyer inState(State.Created) {
s_state = State.Confirmed;
emit Confirmed(i_seller);
i_tokenContract.safeTransfer(i_seller, i_tokenContract.balanceOf(address(this)));
}
function resolveDispute(uint256 buyerAward) external onlyArbiter nonReentrant inState(State.Disputed) {
uint256 tokenBalance = i_tokenContract.balanceOf(address(this));
uint256 totalFee = buyerAward + i_arbiterFee;
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);
}
Impact
confirmReceipt() or resolveDispute will be DoSed if any of the seller,buyer,arbiter is blacklisted.
Tools Used
Manual Review
Recommendations
Should have claim() function where buyer, seller, arbiter would be able to withdraw their claims.
+ mapping(address => uint256) public claimable;
+ function claim() external {
+ uint256 amount = claimable[msg.sender];
+ if (amount > 0)
+ {
+ delete claimable[msg.sender];
+ i_tokenContract.safeTransfer(msg.sender, amount);
+ }
+ }
function confirmReceipt() external onlyBuyer inState(State.Created) {
s_state = State.Confirmed;
emit Confirmed(i_seller);
- i_tokenContract.safeTransfer(i_seller, i_tokenContract.balanceOf(address(this)));
+ claimable[i_seller] = price;
}
function resolveDispute(uint256 buyerAward) external onlyArbiter nonReentrant inState(State.Disputed) {
uint256 tokenBalance = i_tokenContract.balanceOf(address(this));
uint256 totalFee = buyerAward + i_arbiterFee;
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);
- }
+ claimable[i_seller] = price - totalFee;
+ claimable[i_buyer] = buyerAward;
+ claimable[i_arbiter] = i_arbiterFee;