205 lines
6.2 KiB
Markdown
205 lines
6.2 KiB
Markdown
# 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**:
|
|
1. Admin blocks user A using `blockProfile(address A)`
|
|
2. User A's profile is burned and mappings are cleared
|
|
3. User A can immediately call `mintProfile()` to create a new profile
|
|
|
|
**Recommendation**:
|
|
Implement a blacklist mapping to track blocked addresses:
|
|
```solidity
|
|
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**:
|
|
```solidity
|
|
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:
|
|
```solidity
|
|
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:
|
|
```solidity
|
|
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:
|
|
```solidity
|
|
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;` |