DatingDapp

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

`LikeRegistry::userBalances` does not track users balances when a like is done

Summary

The issue is located in function LikeRegistry::likeUser where the user is paying at least 1 ether to like another user. Here we are suppose to add the amount payed into the balance of the user, but this is not being done.

Vulnerability Details

The vulnerability effect is located in LikeRegistry::matchRewards where the mapping userBalances is used to calculate the amount of rewards and the matching fees.

function matchRewards(address from, address to) internal {
----> uint256 matchUserOne = userBalances[from];
----> 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

In order to prove the issue, we can validate that no fees are being collected.
For that, we need to make totalFees public first

- uint256 totalFees;
+ uint256 public totalFees;

And run this test

// SPDX-License-Identifier: MIT
contract LikeRegistryTest is Test {
LikeRegistry likeRegistry;
SoulboundProfileNFT soulboundNFT;
address user1 = address(1);
address user2 = address(2);
function setUp() public {
soulboundNFT = new SoulboundProfileNFT();
likeRegistry = new LikeRegistry(address(soulboundNFT));
}
function testLikeRegistry() public {
// we create the profile for the users
vm.prank(user1);
soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage");
vm.prank(user2);
soulboundNFT.mintProfile("Bob", 26, "ipfs://profileImage");
// user1 likes user2
vm.prank(user1);
vm.deal(user1, 1 ether);
likeRegistry.likeUser{value: 1 ether}(user2);
// we check that no balance is being added to the userBalance
assertEq(likeRegistry.userBalances(user1), 0 ether);
// user2 likes user1
vm.prank(user2);
vm.deal(user2, 1 ether);
likeRegistry.likeUser{value: 1 ether}(user1);
// we check that no balance is being added to the userBalance
assertEq(likeRegistry.userBalances(user2), 0 ether);
// we validate fees are 0
assertEq(likeRegistry.totalFees(), 0 ether);
}
}

Impact

This is happening for every valid matcht and makes the Multisig to be empty. Also the fees collected are going to be zero.

Recommendations

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);
+ userBalances[msg.sender] += msg.value;
// 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 6 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.