DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Invalid

`matchRewards` Function Transfers Excessive ETH Amounts In the LikeRegistry Contract

Summary

The matchRewards function in the LikeRegistry contract transfers the entire balance of matched users instead of only 1 ETH per match. This flaw allows users to lose more ETH than expected, making the system prone to fund mismanagement and unintended financial loss.

Vulnerability Details

The matchRewards function retrieves and transfers the entire balance of the matched users rather than only 1 ETH per match. This is due to the following lines:

uint256 matchUserOne = userBalances[from];
uint256 matchUserTwo = userBalances[to];

These variables store the total user balance instead of just 1 ETH, leading to excessive ETH transfers when a match occurs. If a user has deposited more than 1 ETH across multiple likes, all of it will be used in a single match.

Lack of Refund Mechanism & Fund Locking

  • Once a user is matched, all of their stored ETH is moved to a MultiSig wallet, without any way to withdraw excess funds or reclaim unused ETH.

  • Users cannot cancel a pending match or opt out before their balance is deducted.

No Duplicate Match Tracking

  • A user can match with the same person multiple times since there is no tracking of past matches, allowing potential reward farming and unintended fund loss.

Impact

  • Loss of Excess ETH: Users may lose more ETH than intended, as the contract does not enforce a 1 ETH limit per match.

  • No Fund Recovery: Once ETH is transferred to the MultiSig wallet, it cannot be withdrawn by users.

  • Potential Reward Exploitation: Users could repeatedly match with the same person to farm rewards, increasing the risk of fund misallocation.

Tools Used

  • Manual code review

Recommendations

  1. Limit Transfers to 1 ETH per Match
    Modify the balance deduction logic to only transfer 1 ETH per match:

require(userBalances[from] >= 1 ether, "Insufficient balance");
require(userBalances[to] >= 1 ether, "Insufficient balance");
userBalances[from] -= 1 ether;
userBalances[to] -= 1 ether;

Implement a Refund Mechanism
Add a function allowing users to withdraw unspent ETH before getting matched:

function withdrawFunds() external {
uint256 balance = userBalances[msg.sender];
require(balance > 0, "No funds to withdraw");
userBalances[msg.sender] = 0;
payable(msg.sender).transfer(balance);
}

Track Previous Matches to Prevent Abuse
Introduce a mapping to prevent duplicate matches:

mapping(address => mapping(address => bool)) public hasMatched;

Before adding a new match:

require(!hasMatched[msg.sender][liked], "Already matched before");
hasMatched[msg.sender][liked] = true;
Updates

Appeal created

n0kto Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

Informational or Gas

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

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