DatingDapp

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

Burning or Blocking a profile might lead to locked ETH in LikeRegistry contract

Vulnerability Details

  1. Users can freely burn their profile NFT at any time or be forcefully removed by the protocol owner, who has the authority to burn a user's NFT directly. However, if a user profile gets burnt after spending ETH to like other profiles, their ETH gets permanently stuck in the LikeRegistry contract.


    This happens because there is no function to withdraw the ETH, and once the profile is burned, the user is unable to get matched. The following check in LikeRegistry::likeUser will always revert:

    require(profileNFT.profileToToken(liked) != 0, "Liked user must have a profile NFT");

    This effectively locks the user's ETH in the contract with no way to retrieve it.

  2. This also leads to another issue on the liker's end. If someone liked a user and the user then burns their profile, the liker's ETH is basically stuck in the contract unless they start liking again and find a match.


Impact

  • Users who burn their profiles lose access to their deposited ETH, leading to financial loss.

  • Since there's no withdrawal mechanism, the funds become completely unrecoverable.

  • Users who have already paid to like other profiles cannot get matched because their profile no longer exists.

  • This significantly affects user experience and trust in the protocol.


Tools Used

  • Manual Review


Recommendations

One effective way to prevent this issue is to combine the SoulboundProfileNFT and LikeRegistry contracts. Instead of deploying them independently, inherit LikeRegistry inside SoulboundProfileNFT and modify the functions to refund ETH before burning a profile.

Suggested Fix:

contract SoulboundProfileNFT is LikeRegistry, Ownable {
/* mapping to track user balances */
mapping(address => uint256) public userBalances;
function burnProfile() external {
[...]
// Refund ETH before burning the profile
uint256 refundETH = userBalances[msg.sender];
userBalances[msg.sender] = 0;
(bool success, ) = payable(msg.sender).call{value: refundETH}("");
require(success, "ETH refund failed");
}
function blockProfile(address blockAddress) external onlyOwner {
[...]
// Refund ETH before blocking the profile
uint256 refundETH = userBalances[blockAddress];
userBalances[blockAddress] = 0;
(bool success, ) = payable(blockAddress).call{value: refundETH}("");
require(success, "ETH refund failed");
}
}

Now to mitigate the second issue of the liker getting stuck due to have previously liked a now burnt profile, we can introduce a withdraw function accessible only by the owner of this protocol to handle such cases and return the funds as required.

N.B. - This proposed solution is a suggested mitigation and may not cover all edge cases. The actual implementation may require additional modifications. A thorough review of the entire contract is recommended to ensure a comprehensive fix for this issue.

Updates

Appeal created

n0kto Lead Judge 6 months ago
Submission Judgement Published
Validated
Assigned finding tags:

finding_blocking_or_burning_no_refund_balances_or_multisig

Likelihood: Low, burning with money in it would be a user mistake, and being blocked is Low. Impact: High, loss of funds

Support

FAQs

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