DatingDapp

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

INCORRECT STATE MANAGEMENT FOR USER `LikeRegistry:userBalance` LEADS TO DOS

H-1 INCORRECT STATE MANAGEMENT FOR USER LikeRegistry:userBalance LEADS TO DOS

Description:
The userBalances state variable in LikeRegistry is not properly updated when users send ETH to like other users. While the ETH is received by the contract, the userBalances mapping is never increased. This leads to the matchRewards() function always reading a balance of 0 for both users.

Impact:
This has several severe impacts:

  1. The protocol's fee collection mechanism is completely broken as totalFees will always be 0

  2. The admin cannot withdraw fees since totalFees is always 0, leading to DOS

  3. Users' ETH gets stuck in the contract since LikeRegistry:matchRewards() tries to send 0 ETH to the multisig wallet

  4. The core matching functionality is non-functional as no rewards are distributed

Proof of Concept

First add this line of code in LikeRegistry: getTotalFees

function getTotalFees() external view returns (uint256) {
return totalFees;
}

Test file demonstrating the issue:

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import {Test} from "forge-std/Test.sol";
import {console2} from "forge-std/console2.sol";
import {LikeRegistry} from "../src/LikeRegistry.sol";
import {SoulboundProfileNFT} from "../src/SoulboundProfileNFT.sol";
contract LikeRegistryTest is Test {
LikeRegistry likeRegistry;
SoulboundProfileNFT soulboundProfileNFT;
uint256 initialBalance = 100 ether;
address USER1 = makeAddr("User 1");
address USER2 = makeAddr("User 2");
function setUp() public {
soulboundProfileNFT = new SoulboundProfileNFT();
likeRegistry = new LikeRegistry(address(soulboundProfileNFT));
vm.deal(USER1, initialBalance);
vm.deal(USER2, initialBalance);
}
function test_if_userBalances_is_not_updated() public {
_mintSoulNFT(USER1, "User 1", 20, "https://example.com/image.png");
_mintSoulNFT(USER2, "User 2", 20, "https://example.com/image.png");
_mutualLike(USER1, USER2);
uint256 user1Balance = likeRegistry.userBalances(USER1);
uint256 user2Balance = likeRegistry.userBalances(USER2);
assertEq(user1Balance, initialBalance);
assertEq(user2Balance, initialBalance);
}
function _mutualLike(address user1, address user2) internal {
vm.prank(user1);
likeRegistry.likeUser{value: initialBalance}(user2);
_getBalance(user1);
vm.prank(user2);
likeRegistry.likeUser{value: initialBalance}(user1);
_getBalance(user2);
_getTotalFees();
}
function _mintSoulNFT(address user, string memory name, uint8 age, string memory profileImage) internal {
vm.prank(user);
soulboundProfileNFT.mintProfile(name, age, profileImage);
}
function _getBalance(address user) internal view {
console2.log("address of user:", user);
console2.log("user balance in ca:likeRegister", user.balance);
}
function _getTotalFees() internal view {
console2.log("total fees in ca:likeRegister", likeRegistry.getTotalFees());
}
}

Logs

[FAIL: assertion failed: 0 != 100000000000000000000] test_if_userBalances_is_not_updated() (gas: 1026846)
Logs:
address of user: 0x233F20a935E25f6c993a71F72cCBE72c79A1F7FC
user balance in ca:likeRegister 0
address of user: 0x8993e8FD026fC11Ad77fB612fB3175C4c0C55330
user balance in ca:likeRegister 0
total fees in ca:likeRegister 0

Code Mitigation

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);
// 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.