6.2 KiB
DatingDapp Smart Contract Audit Findings
Overview
This audit was conducted on the DatingDapp smart contract system, which consists of three main contracts:
- SoulboundProfileNFT.sol
- LikeRegistry.sol
- MultiSig.sol
High Severity Findings
[H-01] Blocked Profile Can Bypass Restrictions by Reminting
Contract: SoulboundProfileNFT.sol => this is actually Medium
Description:
The blockProfile function in SoulboundProfileNFT contract fails to permanently prevent blocked addresses from participating in the platform.
Impact:
- Blocked malicious users can immediately create new profiles
- Platform security measures can be circumvented
- Admin actions become ineffective
Proof of Concept:
- Admin blocks user A using
blockProfile(address A) - User A's profile is burned and mappings are cleared
- User A can immediately call
mintProfile()to create a new profile
Recommendation: Implement a blacklist mapping to track blocked addresses:
mapping(address => bool) public blockedAddresses;
function blockProfile(address blockAddress) external onlyOwner {
blockedAddresses[blockAddress] = true;
uint256 tokenId = profileToToken[blockAddress];
require(tokenId != 0, "No profile found");
_burn(tokenId);
delete profileToToken[blockAddress];
delete _profiles[tokenId];
emit ProfileBurned(blockAddress, tokenId);
}
function mintProfile(string memory name, uint8 age, string memory profileImage) external {
require(!blockedAddresses[msg.sender], "Address is blocked");
// ... rest of the function
}
[H-02] Incorrect Balance Management in Match Rewards
Contract: LikeRegistry.sol
Description:
In the matchRewards function, user balances are set to zero before their values are used in calculations, resulting in zero rewards distribution.
Impact:
- Users lose all deposited funds when matched
- No rewards are distributed to matched pairs
- Funds remain locked in the contract
Proof of Concept:
function matchRewards(address from, address to) internal returns (address) {
userBalances[from] = 0; // Balance cleared before use
userBalances[to] = 0; // Balance cleared before use
uint256 matchUserOne = userBalances[from]; // Will always be 0
uint256 matchUserTwo = userBalances[to]; // Will always be 0
// ... rest of the function
}
Recommendation: Store balances in temporary variables before clearing:
function matchRewards(address from, address to) internal returns (address) {
uint256 matchUserOne = userBalances[from];
uint256 matchUserTwo = userBalances[to];
userBalances[from] = 0;
userBalances[to] = 0;
uint256 totalRewards = matchUserOne + matchUserTwo;
// ... rest of the function
}
[H-03] ETH Lock Risk in LikeRegistry
Contract: LikeRegistry.sol => invalid, by design / info
Description:
The receive() function accepts ETH and updates user balances, but there's no mechanism for users to withdraw their funds directly.
Impact:
- User funds can be permanently locked in the contract
- No way to recover accidentally sent ETH
- Potential loss of user funds
Recommendation: Add a withdrawal function for direct deposits:
function withdrawBalance() external {
uint256 amount = userBalances[msg.sender];
require(amount > 0, "No balance to withdraw");
userBalances[msg.sender] = 0;
(bool success,) = payable(msg.sender).call{value: amount}("");
require(success, "Transfer failed");
}
Medium Severity Findings
[M-01] Potential Fund Lock in MultiSig => invalid, info, by design
Contract: MultiSig.sol
Description:
The MultiSig contract lacks recovery mechanisms if one owner becomes unresponsive or loses their keys.
Impact:
- Funds could be permanently locked if one owner is unavailable
- No way to replace or update owners
- No emergency withdrawal mechanism
Recommendation: Implement a timelock mechanism for emergency withdrawals or owner replacement functionality.
[M-02] Missing Profile Update Functionality => invalid
Contract: SoulboundProfileNFT.sol
Description:
Users cannot update their profile information without burning and reminting their NFT.
Impact:
- Poor user experience
- Unnecessary gas costs for profile updates
- Historical data loss when profiles are updated
Recommendation: Add a profile update function with proper access controls.
Low Severity Findings
[L-01] Insufficient Input Validation => invalid
Contract: SoulboundProfileNFT.sol
Description:
- No validation for name length
- No validation for profile image URL format
- No age restrictions or validation
Recommendation: Add proper input validation:
function mintProfile(string memory name, uint8 age, string memory profileImage) external {
require(bytes(name).length > 0 && bytes(name).length <= 50, "Invalid name length");
require(age >= 18 && age <= 100, "Invalid age");
require(bytes(profileImage).length > 0, "Invalid profile image");
// ... rest of the function
}
[L-02] Gas Optimization Issues => not needed
Contracts: All
Description:
- Storage of full profile data on-chain is expensive
- Redundant storage of data that could be emitted as events
- Inefficient string handling in profile data
Recommendation:
- Consider using events for historical data
- Use off-chain storage for profile images
- Optimize string handling and storage patterns
[L-03] Missing Events for Critical Operations => not needed
Contracts: All
Description:
Some state-changing operations lack event emissions, making it difficult to track changes off-chain.
Recommendation: Add events for all significant state changes.
Informational Findings
[I-01] Documentation Gaps => not needed
Contracts: All
Description:
- Limited NatSpec documentation
- Missing function parameter documentation
- Unclear error messages
Recommendation: Improve documentation coverage and clarity.
[I-02] Version Control => not needed
Contracts: All
Description:
Contracts use ^0.8.19 which allows for minor version updates.
Recommendation:
Pin to exact version: pragma solidity 0.8.19;