DatingDapp

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

The `userBalances` mapping in the `LikeRegistry` contract is not being updated, resulting in locked funds for everyone

Severity

Impact: High
Likelihood: High
Severity: High

Vulnerability Details

The LikeRegistry::userBalances mapping is used to determine how many tokens should be allocated to the match’s multiSig and how much in fees should go to the contract owner. However, this mapping is never updated when users like other profiles.

Impact

This results in both users and the protocol owner being unable to access any tokens. The tokens remain locked and unrecoverable within the contract.

Proof of Concept

The following test demonstrates that balances are never updated, leading to an empty multiSig and preventing the owner from withdrawing fees. To aid debugging, an event has been added to the LikeRegistry contract to log the multiSig address.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "forge-std/Test.sol";
import {MultiSigWallet} from "../src/MultiSig.sol";
import {LikeRegistry} from "../src/LikeRegistry.sol";
import {SoulboundProfileNFT} from "../src/SoulboundProfileNFT.sol";
contract LikeRegistryTest is Test {
SoulboundProfileNFT profileNFT;
LikeRegistry likeRegistry;
address loveBird1;
address loveBird2;
address owner;
function setUp() public {
owner = makeAddr("owner");
loveBird1 = makeAddr("loveBird1");
loveBird2 = makeAddr("loveBird2");
vm.deal(payable(loveBird1), 10 ether);
vm.deal(payable(loveBird2), 10 ether);
}
function test_userBalancesNotUpdated() public {
vm.startPrank(owner);
profileNFT = new SoulboundProfileNFT();
likeRegistry = new LikeRegistry(address(profileNFT));
vm.stopPrank();
vm.prank(loveBird1);
profileNFT.mintProfile("Alice", 25, "ipfs://profileImageAlice");
vm.prank(loveBird2);
profileNFT.mintProfile("Bob", 25, "ipfs://profileImageBob");
vm.prank(loveBird1);
likeRegistry.likeUser{value: 1 ether}(loveBird2);
uint256 userBalance = likeRegistry.userBalances(loveBird1);
assertEq(userBalance, 0); //Check user1's userBalance
console.log("User1's balance: ", userBalance); //Should be 1 ether
vm.recordLogs();
vm.prank(loveBird2);
likeRegistry.likeUser{value: 1 ether}(loveBird1);
userBalance = likeRegistry.userBalances(loveBird2);
assertEq(userBalance, 0); //Check user2's userBalance
console.log("User2's balance: ", userBalance); //Should be 1 ether
Vm.Log[] memory logs = vm.getRecordedLogs();
bytes32 walletAddressBytes = logs[2].topics[1];
address multiSigWalletAddress = address(uint160(uint256(walletAddressBytes)));
uint256 balance = address(multiSigWalletAddress).balance;
assertEq(balance, 0); //Check the multiSigs balance
console.log("MultiSig's balance: ", balance); //Should be 1.8 ether
vm.prank(owner);
vm.expectRevert(); //When there is no fees accumulated, withdrawFees should revert
likeRegistry.withdrawFees();
assertEq(owner.balance, 0); //Check the owner's balance
console.log("Owner's balance: ", owner.balance); //Should be 0.2
}
}

Tools Used

Manual Review

Recommendations

Update the userBalances after a user likes another profile.
Modify the LikeRegistry::likeUser function as follows:

likes[msg.sender][liked] = true;
+ userBalances[msg.sender] += msg.value;
emit Liked(msg.sender, liked);
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.