LikeRegistry collects 1 ETH per like but never credits it to userBalances. When a match triggers, matchRewards() reads 0 for both users and deploys an empty MultiSig. All ETH is trapped.
likeUser() accepts msg.value >= 1 ether but the function body never writes to userBalances[msg.sender]:
matchRewards() reads userBalances[from] and userBalances[to], both 0. The MultiSig wallet receives 0 ETH. withdrawFees() reverts because totalFees is also 0. No recovery function exists.
Likelihood:
Every call to likeUser() triggers this bug. There are no edge cases or special conditions — the balance is simply never updated. The bug is present from deployment and the first user to send ETH loses it.
Impact:
100% of ETH sent to the contract is permanently locked. Matched users receive empty MultiSig wallets. The owner collects zero fees. There is no admin rescue function, so the ETH is irrecoverable without a contract upgrade or migration.
The test below shows Alice and Bob each sending 1 ETH via likeUser(). After the match triggers, the contract still holds all 2 ETH because userBalances was never credited. The owner's withdrawFees() also reverts because totalFees is 0.
Add the missing balance update in likeUser() so that each user's ETH is tracked and available for matchRewards() to distribute. This single line restores the entire reward flow — matches will deploy funded MultiSig wallets and the owner will collect fees.
## 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.