likeUser() is payable and requires the caller to send at least 1 ETH, but the function body never records that ETH against the user. There is no userBalances[msg.sender] += msg.value anywhere:
When a mutual like triggers matchRewards, it reads userBalances[from] and userBalances[to] - both still 0 - so totalRewards is 0, the freshly deployed multisig receives 0, and totalFees never grows. The entire premise ("all previous like payments are pooled into the match's multisig") fails. Worse, every 1+ ETH a user sends to likeUser simply accumulates in the contract with no accounting and no withdrawal path: matchRewards distributes the (zero) balances and withdrawFees can only pay out totalFees (also 0). All ETH deposited via likes is permanently locked.
Likelihood: High - occurs on every single likeUser call; it is the only way to use the protocol.
Impact: High - 100% of user deposits are orphaned with no recovery path, and matched couples receive nothing. Total loss of all funds flowing through the protocol.
Two users mint profiles and like each other with 1 ETH each. Their balances are never credited, the match pays out 0, and 2 ETH is stuck in the registry. Runnable, self-contained Foundry test:
Run forge test --mt test_PoC_likeUserNeverCreditsBalances -vv; it passes - 2 ETH is trapped and the match paid out nothing.
Credit each like payment to the sender's balance so matchRewards has funds to pool. The corrected function:
Why this fixes it: with userBalances[msg.sender] += msg.value, each deposit is tracked, so matchRewards pools the correct totals into the multisig and totalFees accrues the 10% cut. Additionally, add a user-facing withdraw() so deposits from likes that never become a mutual match can be reclaimed - otherwise unmatched likers' ETH would still be stuck even with correct accounting.
## 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.