When a user funds the contract by calling the likeUser() function and attaching Ether (e.g., 1 ETH), the contract is expected to track these deposited funds to be used by the internal matchRewards() function. This internal function is responsible for calculating and sending the pooled funds to a newly deployed MultiSig contract.
Issue: Although the contract defines a userBalances mapping (address => uint256), it completely fails to update this mapping with the msg.value sent by the user during the likeUser() execution.
Likelihood:
Because the contract lacks the logic to record the incoming msg.value, userBalances[user] will always evaluate to 0. Consequently, when a match occurs and matchRewards() is triggered, the reward calculation will always be based on a zero balance, resulting in exactly 0 ETH being sent to the deployed MultiSig. This will happen on 100% of all funded matches.
Impact:
Impact (High): Because the MultiSig wallet receives 0 ETH, the actual Ether deposited by the users becomes permanently locked inside the LikeRegistry contract. Without a way to properly account for or withdraw these stuck funds, users suffer a complete loss of their deposited Ether.
The following Foundry test demonstrates the complete failure of the contract's internal accounting. In the test, two users (Alice and Spider) both call likeUser and send 1 Ether each, resulting in a successful match. The assertions prove two critical facts:
The internal `userBalances` mapping for both users remains exactly `0`, meaning the contract failed to record their deposits.
The LikeRegistry contract's actual Ether balance is exactly 2 ether, proving that the contract swallowed the funds and permanently locked them instead of forwarding them to the MultiSig wallet as intended.
Resolve this issue, the contract must correctly account for the Ether deposited by users when they initiate a like.
Update the likeUser function to increment the caller's internal balance by the msg.value they sent. This update must happen before any matching logic or external calls are executed.
## 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.