DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: high
Valid

[H-01] UserBalance is not updated in `LikeRegistry::likeUser()`

Description:

The LikeRegistry::likeUser() is intended to register a "like" between users while requiring a minimum deposit of 1 ETH. However, it fails to update the sender’s balance in the contract. As a result, users cannot later redeem or use their deposited funds.

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);
}
}

Impact:

Critical. This issue occurs every time a user likes another user. The missing balance update effectively locks user funds in the contract, breaking a fundamental part of the protocol's functionality.

Proof of Concept:

The following test case, testUserBalance(), demonstrates the issue. It checks whether the userBalances mapping is updated when a user sends ETH while liking another user.

LikeRegistry likeRegistry;
SoulboundProfileNFT soulboundNFT;
address user = address(0x123);
address user2 = address(0x456);
address user3 = address(0x789);
address owner = address(this); // Test contract acts as the owner
uint256 public constant STARTING_USER_BALANCE = 10e18;
function setUp() public {
soulboundNFT = new SoulboundProfileNFT();
likeRegistry = new LikeRegistry(address(soulboundNFT));
vm.deal(user, STARTING_USER_BALANCE);
vm.deal(user2, STARTING_USER_BALANCE);
vm.deal(user3, STARTING_USER_BALANCE);
}
function testUserBalance() public {
vm.startPrank(user); // Simulates user calling the function
soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage");
vm.stopPrank();
vm.startPrank(user2);
soulboundNFT.mintProfile("Bob", 30, "ipfs://profileImage");
likeRegistry.likeUser{value: 1 ether}(user);
vm.stopPrank();
assertEq(likeRegistry.likes(user2, user), true);
assertEq(likeRegistry.userBalances(user2), 1 ether);
}

Recommended Mitigation:

To ensure user balances are properly tracked, update the userBalances mapping when a user sends ETH to like another user.
Modify the likeUser() function to include:

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"
);
+ userBalances[msg.sender] += msg.value;
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);
}
}
Updates

Appeal created

n0kto Lead Judge 7 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_likeUser_no_userBalances_updated

Likelihood: High, always. Impact: High, loss of funds

Support

FAQs

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