DatingDapp

AI First Flight #6
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: medium
Likelihood: high
Invalid

Full user balance is consumed on the first match instead of charging 1 ETH per like, causing unintended fee amplification and loss of remaining likes

Root + Impact

Description

  • According to the protocol design, users must pay 1 ETH to like another profile. If two users mutually like each other, their contributions are pooled and transferred to a shared multisig wallet after deducting a 10% protocol fee.

  • However, the contract allows users to send any amount ≥ 1 ETH when calling likeUser(). The deposited ETH is tracked in userBalances and later used in matchRewards(). When a match occurs, the matchRewards() function consumes the entire recorded balance of both users instead of deducting 1 ETH per match.

  • This means that if a user accidentally sends more ETH than intended when liking someone, the full balance will be used for the first match and the protocol fee will be calculated from the entire balance instead of the intended 1 ETH.

// The matchRewards() function calculates rewards using the full balance stored in userBalances.
uint256 matchUserOne = userBalances[from];
uint256 matchUserTwo = userBalances[to];
userBalances[from] = 0;
userBalances[to] = 0;
uint256 totalRewards = matchUserOne + matchUserTwo;
uint256 matchingFees = (totalRewards * FIXEDFEE) / 100;
// Because the full balances are used, a single match can consume all ETH deposited by the user, even if the user intended to use that ETH for multiple likes.

Risk

Likelihood:

  • Users can send more than 1 ETH when calling likeUser() because the contract only enforces msg.value >= 1 ether. Accidental overpayment is possible when interacting directly with contracts or through custom integrations.

Impact:

  • Protocol fees are calculated from the entire balance, potentially causing users to pay significantly higher fees than expected.

  • The full user balance is consumed during the first match instead of charging 1 ETH per match.

  • Remaining intended likes cannot be executed because the balance is reset to zero after the first match.

Proof of Concept

User A deposits 4 ETH when liking User B
User B deposits 1 ETH when liking User A
matchRewards executes
totalRewards = 5 ETH
matchingFees = 0.5 ETH (10%)
rewards = 4.5 ETH
userBalances[A] = 0
userBalances[B] = 0

Recommended Mitigation

// Update the current code to consider likeCost = 1 ether and instead of calculating fee as the 10% of the whole balance.
- uint256 matchUserOne = userBalances[from];
- uint256 matchUserTwo = userBalances[to];
- userBalances[from] = 0;
- userBalances[to] = 0;
- uint256 totalRewards = matchUserOne + matchUserTwo;
+ uint256 likeCost = 1 ether;
+
+ require(userBalances[from] >= likeCost);
+ require(userBalances[to] >= likeCost);
+
+ userBalances[from] -= likeCost;
+ userBalances[to] -= likeCost;
+
+ uint256 totalRewards = likeCost * 2;
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 2 hours ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

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

Give us feedback!