DatingDapp

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

H-02. Giving a like to another profile does not record the ETH balance

Summary

Executing LikeRegistry::likeUser requires a payment, but the payment is not recorded in userBalances. As a result, any other functions that rely on userBalances will have incorrect logic.

Vulnerability Details

LikeRegistry::likeUser requires 1 ETH or more to be sent to the contract, but it is not recorded in the balance variable.

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

In LikeRegistry::matchRewards, since the balance is not recorded, the matchUserOne and matchUserTwo variables are always 0.

function matchRewards(address from, address to) internal {
// matchUserOne is always 0
uint256 matchUserOne = userBalances[from];
// matchUserTwo is always 0
uint256 matchUserTwo = userBalances[to];
userBalances[from] = 0;
userBalances[to] = 0;
uint256 totalRewards = matchUserOne + matchUserTwo;
uint256 matchingFees = (totalRewards * FIXEDFEE) / 100;
uint256 rewards = totalRewards - matchingFees;
totalFees += matchingFees;
// Deploy a MultiSig contract for the matched users
MultiSigWallet multiSigWallet = new MultiSigWallet(from, to);
// Send ETH to the deployed multisig wallet
(bool success,) = payable(address(multiSigWallet)).call{value: rewards}("");
require(success, "Transfer failed");
}

POC

function testlikeUserBalance() public {
vm.prank(user1);
soulboundNFT.mintProfile("user1", 10, "ipfs://profileImage");
vm.prank(user2);
soulboundNFT.mintProfile("user2", 20, "ipfs://profileImage");
hoax(user1, 1 ether);
likeRegistry.likeUser{value: 1 ether}(user2);
hoax(user2, 1 ether);
likeRegistry.likeUser{value: 1 ether}(user1);
// User1's balance is 0 after executing likeUser
uint256 balance1 = likeRegistry.userBalances(user1);
assertEq(balance1, 0 , "Balance1 is not equal to 0");\
// User2's balance is 0 after executing likeUser
uint256 balance2 = likeRegistry.userBalances(user2);
assertEq(balance2, 0 , "Balance2 is not equal to 0");
}

Impact

In LikeRegistry::matchRewards, the balances of the matched users are always 0, preventing the correct amount of funds from being transferred to the shared multisig wallet. This severely impacts the contract's functionality.

Tools Used

Manual review

Foundry for POC

Recommendations

Record userBalances when calling LikeRegistry::likeUser.

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.