Under normal behavior, every user who calls likeUser() with at least 1 ether should have that payment tracked so that, if a mutual match happens later, both users’ prior like payments can be pooled and forwarded to the newly created MultiSigWallet after deducting the protocol fee.
The issue is that likeUser() accepts ETH but never credits msg.value into userBalances[msg.sender].
As a result, when a mutual like occurs, matchRewards() calculates rewards from two zero balances:
Because userBalances is never updated, both matchUserOne and matchUserTwo are always 0, so:
\
the matched users receive 0 ETH\
the protocol fee is also 0\
the ETH paid into likeUser() remains stuck in LikeRegistry
This breaks the core product promise described in the project README, where mutual likes are supposed to pool prior payments into a shared date wallet.
Likelihood:
Reason 1 // This occurs every time two users mutually like each other, because the contract logic never stores the ETH paid through likeUser().
Reason 2 // This occurs in the normal intended application flow and does not require privileged access, uncommon token behavior, or any special timing condition.Impact:
Impact 1 // Matched users do not receive the pooled funds they paid for, so the main reward mechanism of the protocol fails completely.
Impact 2 // ETH becomes trapped inside LikeRegistry, while neither the matched users nor the owner can recover it through the intended reward or fee paths.
Steps to reproduce
1. Mint a profile NFT for Alice.
2. Mint a profile NFT for Bob.
3. Alice calls likeUser(bob) with 1 ether.
4. Bob calls likeUser(alice) with 1 ether.
5. Observe that the mutual match is recorded.
6. Observe that userBalances[alice] == 0 and userBalances[bob] == 0.
7. Observe that the contract still holds the full 2 ether.
8. Observe that no usable rewards were forwarded to the match wallet.
## 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); [...] } ```
The contest is live. Earn rewards by submitting a finding.
Submissions are being reviewed by our AI judge. Results will be available in a few minutes.
View all submissionsThe contest is complete and the rewards are being distributed.