DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: medium
Valid

Incorrect ETH Deduction in `LikeRegistry::matchRewards`, Leading to Fund Mismanagement, Where All User's Eth Is Sent To The First Multisig

Summary

The LikeRegistry::matchRewards function incorrectly deducts the entire balance of users when a mutual match occurs, instead of deducting 1 ETH per match. This causes a user’s ETH to be fully drained on their first match, leaving no funds for subsequent matches.

Vulnerability Details

Root Cause:

  • When a mutual like occurs (e.g., User A likes User B, and User B likes User A), the matchRewards function calculates rewards using the total balance of both users (userBalances[from] and userBalances[to]), then resets their balances to zero.

  • This design flaw causes all of a user’s ETH to be sent to the first multisig wallet created for their earliest match, even if they have multiple matches.

Example Scenario:

  1. User A sends 3 ETH to like three different users (B, C, D).

  2. B, C, and D later like A back, creating three mutual matches.

  3. On the first match (A ↔ B), the matchRewards function:

    • Takes A’s entire balance (3 ETH) and B’s balance (1 ETH).

    • Sends 3.6 ETH (4 ETH total - 10% fee) to the A-B multisig wallet.

    • Resets both A and B’s balances to zero.

  4. Subsequent matches (A ↔ C, A ↔ D) receive zero ETH because A’s balance is already drained.

Impact

  1. Loss of User Funds: Users lose ETH intended for multiple matches (e.g., 3 ETH sent for 3 matches is consumed by the first match).

  2. Broken Matching Logic: Only the first match receives ETH, rendering the protocol unusable for users with multiple matches.

  3. Protocol Reputation Risk: Users will lose trust in the platform due to fund mismanagement.

Tools Used

  • Manual code review.

Recommendations

Modify the matchRewards function to deduct 1 ETH per match instead of the entire balance:

function matchRewards(address from, address to) internal {
- uint256 matchUserOne = userBalances[from];
- uint256 matchUserTwo = userBalances[to];
- userBalances[from] = 0;
- userBalances[to] = 0;
+ // Deduct 1 ETH from each user for this specific match
+ uint256 amountPerUser = 1 ether;
+ require(userBalances[from] >= amountPerUser, "Insufficient balance for from");
+ require(userBalances[to] >= amountPerUser, "Insufficient balance for to");
+
+ userBalances[from] -= amountPerUser;
+ userBalances[to] -= amountPerUser;
- uint256 totalRewards = matchUserOne + matchUserTwo;
+ uint256 totalRewards = amountPerUser + amountPerUser; // 2 ETH total
uint256 matchingFees = (totalRewards * FIXEDFEE ) / 100;
uint256 rewards = totalRewards - matchingFees;
totalFees += matchingFees;
MultiSigWallet multiSigWallet = new MultiSigWallet(from, to);
(bool success, ) = payable(address(multiSigWallet)).call{value: rewards}("");
require(success, "Transfer failed");
}
Updates

Appeal created

n0kto Lead Judge 3 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_several_match_lead_to_multisig_with_no_funds

Likelihood: Medium, if anyone has 2 matches or more before reliking. Impact: Medium, the user won't contribute to the wallet.

Support

FAQs

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