DatingDapp

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

`LikeRegistry::likeUser` doesn't update `userBalances`

Summary

Although the likeUser function is a payable function and can receive ether, it has no means to keep track of the payment made by users whenever they like another user's profile

Vulnerability Details

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

The LikeRegistry contract has a mapping userBalances that maps the address of users to the amount deposited/paid which is meant to be updated whenever a user like another user's profile. But userBalances was not updated in the likeUser function

Impact

userBalances was used in matchRewards to get the amount paid by each user involved in a match and was used in calculating reward and totalFees. This results in severe disruption of the protocol's functionality as there would be no fee and no reward to send to the multiSig Wallet

Place the code below in testSoulboundProfileNFT.t.sol:

PoC
function testWithdrawFees() public {
vm.prank(user);
soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage");
vm.prank(user2);
soulboundNFT.mintProfile("Alex", 24, "ipfs://profileImage");
uint256 ownerInitialBalance = address(likeRegistry).balance;
console.log('Owners Initial Balance:', ownerInitialBalance);
vm.deal(user, 2 ether);
vm.deal(user2, 2 ether);
vm.prank(user);
likeRegistry.likeUser{value: 1 ether}(user2);
vm.prank(user2);
likeRegistry.likeUser{value: 1 ether}(user);
vm.prank(owner);
likeRegistry.withdrawFees();
uint256 fees = address(likeRegistry).balance;
assertEq(ownerInitialBalance, 0);
assertEq(fees, 0.2 ether);
}
`fees` returns 0 because there is no fee to withdraw

Tools Used

Manual Review

Recommendations

Update userBalances mapping whenever a user likes another's profile

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.