DatingDapp

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

[H-1] Lack of Tracking for the ```userBalances``` mapping in ```LikeRegistry.sol``` Disrupts the Protocol's Functionality

Description:

In LikeRegistry.sol, we find the core logic of the protocol, where users can like each other and get matched. To perform a like, a user must pay at least 1 ETH by calling the function likeUser(address liked).

A crucial part of the protocol is the tracking of user payments using the userBalances() mapping. This mapping records the amount of ETH each user has paid, which is later used to create an instance of MultiSigWallet.sol and transfer the correct funds from both matched users to the MultisigWallet.

The issue arises because LikeRegistry::likeUser() does not update the userBalances mapping. As a result, the stored balance remains zero, even if users pay ETH to the protocol. This flaw has two major consequences:

  1. Locked Funds – The ETH sent by users cannot be accessed, as the protocol relies on userBalances to track amounts for MultiSigWallet transfers.

  2. Fee Withdrawal Failure – The protocol calculates fees based on userBalances, meaning that if the balance remains zero, the fees will also be zero, preventing the contract owner from withdrawing them.

Ultimately, this breaks the entire financial flow of the protocol, leading to permanently locked funds and an inoperable fee system.

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;
@> //Missing update of mapping userBalances();
emit Liked(msg.sender, liked);
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:

The impact of this issue is critical, as the funds paid by users will be permanently locked, and the core functionalities of the protocol will be disrupted.

The likelihood of this issue occurring is also high, as it will consistently affect every transaction.

Proof of Concept:

PoC
function test__audit__noTrackingOfUserBalancesCriticalError() public {
//Minting nfts for each user
vm.prank(user); // Simulates user calling the function
soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage");
vm.prank(user2); // Simulates user calling the function
soulboundNFT.mintProfile("David", 26, "ipfs://profileImage");
//user will like user2
vm.prank(user);
likeRegistry.likeUser{value: 1 ether}(address(user2));
uint256 balancesOfUserPayed = likeRegistry.userBalances(address(user));
console.log(
"Balance of the userBalance(user) after first payment: ",
balancesOfUserPayed
);
uint256 balanceOfCOntract = (address(likeRegistry)).balance;
console.log(
"LikeRegistry balance after first payment: ",
balanceOfCOntract
);
assert(likeRegistry.likes(address(user), address(user2)) == true);
//user2 will like user
vm.prank(user2);
likeRegistry.likeUser{value: 1 ether}(address(user));
uint256 balanceOfCOntractAfterSendingToMultisig = address(likeRegistry)
.balance;
// Balance of LikeRegistry SC is still 2 ether. Meaning the lack of tracking userBlances mapping is
// breaking the protocol.
console.log(
"LikeRegistry balance after creatingand sending to multisig: ",
balanceOfCOntractAfterSendingToMultisig
);
// Not passing this test, because the lack of tracking userBlance breaks the Protocol
assert(balanceOfCOntractAfterSendingToMultisig < balanceOfCOntract);
}

Recommended Mitigation:

To mitigate this issue we encourage you to add an update of the userBalances() mapping inside the
LikeRegistry::likeUser() function.

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);
if (likes[liked][msg.sender]) {
// e pushea tanto en uno como en otro array en mathces mapping
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.