DatingDapp

AI First Flight #6
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Severity: high
Valid

likeUser accepts >= 1 ETH but never credits userBalances, so matched rewards are always zero and every liker's ETH is permanently locked

likeUser accepts ETH but never credits userBalances, so deposits are never recorded

Description

LikeRegistry.likeUser is payable and requires at least 1 ETH (line 32), but it never writes the received msg.value into the userBalances mapping (line 22). The mapping is therefore only ever read and zeroed in matchRewards (lines 51-54), never incremented, so the contract's accounting of who deposited what is permanently empty.

function likeUser(address liked) external payable {
require(msg.value >= 1 ether, "Must send at least 1 ETH");
// ... checks ...
likes[msg.sender][liked] = true;
// @> msg.value is received but userBalances[msg.sender] is never incremented
emit Liked(msg.sender, liked);

Risk

Likelihood: Every single call to likeUser triggers this. There is no code path in the contract that ever writes a non-zero value into userBalances, so the bug occurs deterministically on 100% of likes.

Impact: Because deposit accounting is missing, on a mutual match matchUserOne and matchUserTwo (lines 51-52) both read 0, totalRewards is 0, and the freshly deployed MultiSigWallet is funded with 0 ETH (line 65). Meanwhile the real ETH each user sent accumulates in LikeRegistry with no withdrawal path that can reach it (withdrawFees only forwards totalFees, which is also 0). The core reward mechanism is fully broken and user funds are stranded.

Proof of Concept

Two users like each other; assert the deployed multisig receives nothing despite 2 ETH being sent in.

function test_userBalancesNeverCredited() public {
// alice and bob both have profiles
vm.prank(alice);
registry.likeUser{value: 1 ether}(bob);
vm.prank(bob);
registry.likeUser{value: 1 ether}(alice); // mutual -> matchRewards
assertEq(registry.userBalances(alice), 0);
assertEq(registry.userBalances(bob), 0);
assertEq(address(registry).balance, 2 ether); // ETH stuck, nothing forwarded
}

Recommended Mitigation

Credit the sender's balance with the ETH actually received inside likeUser.

function likeUser(address liked) external payable {
require(msg.value >= 1 ether, "Must send at least 1 ETH");
// ... checks ...
- likes[msg.sender][liked] = true;
+ userBalances[msg.sender] += msg.value;
+ likes[msg.sender][liked] = true;
emit Liked(msg.sender, liked);
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 2 hours ago
Submission Judgement Published
Validated
Assigned finding tags:

[H-01] After the user calls the `likeUser` function, the userBalance does not increase by the corresponding value.

## Description User A calls `likeUser` and sends `value > 1` ETH. According to the design of DatingDapp, the amount for user A should be accumulated by `userBalances`. Otherwise, in the subsequent calculations, the balance for each user will be 0. ## Vulnerability Details When User A calls `likeUser`, the accumulation of `userBalances` is not performed. ```solidity function likeUser( address liked ) external payable { require(msg.value >= 1 ether, "Must send at least 1 ETH"); require(!likes[msg.sender][liked], "Already liked"); require(msg.sender != liked, "Cannot like yourself"); require(profileNFT.profileToToken(msg.sender) != 0, "Must have a profile NFT"); require(profileNFT.profileToToken(liked) != 0, "Liked user must have a profile NFT"); likes[msg.sender][liked] = true; emit Liked(msg.sender, liked); // Check if mutual like if (likes[liked][msg.sender]) { matches[msg.sender].push(liked); matches[liked].push(msg.sender); emit Matched(msg.sender, liked); matchRewards(liked, msg.sender); } } ``` This will result in `totalRewards` always being 0, affecting all subsequent calculations: ```solidity uint256 totalRewards = matchUserOne + matchUserTwo; uint256 matchingFees = (totalRewards * FIXEDFEE ) / 100; uint256 rewards = totalRewards - matchingFees; totalFees += matchingFees; ``` ## POC ```solidity function testUserBalanceshouldIncreaseAfterLike() public { vm.prank(user1); likeRegistry.likeUser{value: 20 ether}(user2); assertEq(likeRegistry.userBalances(user1), 20 ether, "User1 balance should be 20 ether"); } ``` Then we will get an error: ```shell [FAIL: User1 balance should be 20 ether: 0 != 20000000000000000000] ``` ## Impact - Users will be unable to receive rewards. - The contract owner will also be unable to withdraw ETH from the contract. ## Recommendations Add processing for `userBalances` in the `likeUser` function: ```diff function likeUser( address liked ) external payable { require(msg.value >= 1 ether, "Must send at least 1 ETH"); require(!likes[msg.sender][liked], "Already liked"); require(msg.sender != liked, "Cannot like yourself"); require(profileNFT.profileToToken(msg.sender) != 0, "Must have a profile NFT"); require(profileNFT.profileToToken(liked) != 0, "Liked user must have a profile NFT"); likes[msg.sender][liked] = true; + userBalances[msg.sender] += msg.value; emit Liked(msg.sender, liked); [...] } ```

Support

FAQs

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

Give us feedback!