DatingDapp

AI First Flight #6
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Severity: high
Valid

Permanent loss of user rewards and protocol accounting corruption.

Root + Impact

The Contract (LikeRegistry.sol) does not Credits User Deposits by not updating state mapping userBalances.

Description

in the https://github.com/CodeHawks-Contests/2025-02-datingdapp/blob/878bd34ef6607afe01f280cd5aedf3184fc4ca7b/src/LikeRegistry.sol#L31 function a User pay sends value:
https://github.com/CodeHawks-Contests/2025-02-datingdapp/blob/878bd34ef6607afe01f280cd5aedf3184fc4ca7b/src/LikeRegistry.sol#L32
but the deposited ETH is never updated in the state variable mapping https://github.com/CodeHawks-Contests/2025-02-datingdapp/blob/878bd34ef6607afe01f280cd5aedf3184fc4ca7b/src/LikeRegistry.sol#L22
As a result in the https://github.com/CodeHawks-Contests/2025-02-datingdapp/blob/878bd34ef6607afe01f280cd5aedf3184fc4ca7b/src/LikeRegistry.sol#L50 function, the following lines:
https://github.com/CodeHawks-Contests/2025-02-datingdapp/blob/878bd34ef6607afe01f280cd5aedf3184fc4ca7b/src/LikeRegistry.sol#L51
https://github.com/CodeHawks-Contests/2025-02-datingdapp/blob/878bd34ef6607afe01f280cd5aedf3184fc4ca7b/src/LikeRegistry.sol#L52
will always return zero for every user.
Consequencely supposing a match occurs:
totalRewards = 0;
matchingFees = 0;
rewards = 0;
yet the ETH paid by users is not refelcted in any protocol accounting.
The protocol's internal accounting becomes completely disconnected from actual funds held.
// Root cause in the codebase with @> marks to highlight the relevant section

Risk

Likelihood:

It is highly likely as it only invloves interaction from users for this bug to mess with the protoco accounting.

Impact:

Eventhough Users pay ETH, they receive no reward and also Fees are unable to be collected. Matching logic operates on zero balances whilst ETH sent to the MultiSig contract accumulates indefinitely and remains trapped, this is a protocol-breaking accounting failure.

Proof of Concept

ser A calls the likeUser(...) function with User B address as the liked profile, ETH is taken fromm User A but noupdate is made to balances. User B likewise calls likeUser(...) function with User A's address as its like address, also pays 1ETH and also user b alance not updated. Once its a mutual like the matchRewards(...) is called wherein Protocol fee is calcuated and added to state. But no fee can be taken as both users balances does reflect zero.
function test_likeUserZeroBalances() public {
uint256 userBalB4 = _likeregistry.userBalances(user);
uint256 userBalAF;
vm.startPrank(user2);
soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage");
vm.stopPrank();
vm.startPrank(user);
soulboundNFT.mintProfile("James", 25, "ipfs://profileImage1");
_likeregistry.likeUser{value: 1 ether}(user2);
vm.stopPrank();
vm.startPrank(user2);
_likeregistry.likeUser{value: 1 ether}(user);
//vm.expectRevert();
_wallet.submitTransaction(user2, 1e18);
vm.stopPrank();
userBalAF = _likeregistry.userBalances(user);
assertEq( userBalB4, 0);
assertEq(userBalAF, 0);
}

Recommended Mitigation

userBalances[msg.sender] += msg.value; is missing, immediately funds are received in the likeUser(...) function state has to b e updated.
userBalances[msg.sender] += msg.value; + add this code
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge about 2 hours ago
Submission Judgement Published
Validated
Assigned finding tags:

[H-01] After the user calls the `likeUser` function, the userBalance does not increase by the corresponding value.

## 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); [...] } ```

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!