LikeRegistry.likeUser accepts at least 1 ether from every liker, but it never credits msg.value to userBalances[msg.sender]. Later, matchRewards reads both balances as zero, so it deploys a multisig and transfers zero ETH while every payment remains trapped in LikeRegistry.
In src/LikeRegistry.sol:31-47, the function records only the boolean like. There is no balance update after receiving ETH. In src/LikeRegistry.sol:50-66, rewards are calculated exclusively from userBalances[from] and userBalances[to].
A simple sequence proves the loss:
Alice calls likeUser(Bob) with 1 ether.
Bob calls likeUser(Alice) with 1 ether.
The mutual-like branch calls matchRewards, which reads 0 for both users.
The multisig receives 0, while 2 ether remains in the registry with no user withdrawal path.
Every normal use locks all like payments. Matched users receive none of the promised pooled funds and there is no recovery mechanism.
Credit the payment before checking for a mutual match:
userBalances[msg.sender] += msg.value;
Then keep the existing checks-effects-interactions order in matchRewards.
Have two profiled users like each other with 1 ether each and assert that the created multisig receives 1.8 ether, totalFees becomes 0.2 ether, and both user balances are zero.
## 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.