DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Invalid

We do not store the records of the multisignature wallet each user has. The `LikeRegistry::matchRewards` function creates a multisignature wallet, however the owners do not get the address or how to interact with the wallet.

Summary

In the `LikeRegistry::matchRewards` function, we do not return anything, not even the wallet address. The implication of this is that a wallet is created, but there is no way to interact with the wallet.

Vulnerability Details

Proof of Concept:

1. UserA likes UserB.
2. UserB likes UserA back.
3. A multisignature wallet is created for UserA and UserB, but they do not have access to the contract created. Hence, the money is sent to a contract we don't have access to.

Proof of Code:

<details>
<summary>Code</summary>
Add the following code to the `testSoulboundProfileNFT.t.sol` file.
```javascript
// Please update your likeUser function for this test to pass
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[liked] += msg.value;
likes[msg.sender][liked] = true;
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);
}
}
function testMultisignatureWalletInfoNotRetrievable() public {
LikeRegistry userRegistry = new LikeRegistry(address(soulboundNFT));
vm.prank(user); // Simulates user calling the function
soulboundNFT.mintProfile("Alice", 25, "ipfs://profileImage");
vm.prank(user2); // Simulates user2 calling the function
soulboundNFT.mintProfile("Ochuko", 24, "ipfs://profileImage");
vm.deal(user, 2 * TRANSFER_AMOUNT);
vm.deal(user2, 2 * TRANSFER_AMOUNT);
vm.prank(user);
userRegistry.likeUser{value: TRANSFER_AMOUNT}(user2);
vm.prank(user2);
userRegistry.likeUser{value: TRANSFER_AMOUNT}(user);
uint256 amountLeftAfterSendingToMultiSigAccount = (2 * TRANSFER_AMOUNT * 10) / 100;
assertEq(amountLeftAfterSendingToMultiSigAccount, address(userRegistry).balance);
}
```
</details>

Impact

The impact of this is that the funds of the two matched users will be sent to a multisignature wallet we do not have access or control to. This leads to a loss of funds as the money sent to wallet cannot be withdrawn since we don't know the contract.

Recommendations

To fix this, we can update `LikeRegistry::matchRewards` && `LikeRegistry::likeUser` function to return the multiSignatureWallet. The whole issue stems from here [LikeRegistry::matchRewards](https://github.com/CodeHawks-Contests/2025-02-datingdapp/blob/878bd34ef6607afe01f280cd5aedf3184fc4ca7b/src/LikeRegistry.sol#L62)

```diff
- function matchRewards(address from, address to) internal {
+ function matchRewards(address from, address to) internal returns(MultiSigWallet){
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");
+ return multiSigWallet;
}
- function likeUser(address liked) external payable {
+ function likeUser(address liked) external payable returns(MultiSigWallet multiSigWallet) {
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);
if (likes[liked][msg.sender]) {
matches[msg.sender].push(liked);
matches[liked].push(msg.sender);
emit Matched(msg.sender, liked);
- matchRewards(liked, msg.sender);
+ multiSigWallet = matchRewards(liked, msg.sender);
}
return multiSigWallet;
}
```
Updates

Appeal created

n0kto Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

Informational or Gas

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.