Beginner FriendlyFoundryNFT
100 EXP
View results
Submission Details
Severity: medium
Valid

**Wrong result in `Soulmate::totalSouls` function, could cause a participant to enter again and be his own soulmate**

  • Wrong result in Soulmate::totalSouls function, could cause a participant to enter again and be his own soulmate

    • Description:

    • If an USER call the Soulmate::totalSouls to see the numbers of participants before apply on Soulmate::mintSoulmateToken, and apply being the soulmate[0], when the USER checks Soulmate::totalSouls again, the value will be the same. So the user could try Soulmate::mintSoulmateToken again and he will became his own soulmate.

    • Impact:

    • This problem could cause many people to became their own soulmates.

    • Proof of Code:

      1. USER call the Soulmate::totalSouls

      2. Receive a number

      3. Call Soulmate::mintSoulmateToken

      4. If the USER is the soulmate[0], he will call Soulmate::totalSouls and receive the same number

      5. User could call Soulmate::mintSoulmateToken again, trying to enter on a second time.

      6. Now the Soulmate::totalSouls will update. However, the user will be his own soulmate.

      Add the code bellow to `Soulmate.t.sol` file
      function test_MintNewTokenTotalSouls() public {
      vm.prank(soulmate1);
      soulmateContract.mintSoulmateToken();
      vm.prank(soulmate2);
      soulmateContract.mintSoulmateToken();
      assertTrue(totalSouls == 2);
      vm.prank(soulmate3);
      soulmateContract.mintSoulmateToken();
      uint256 totalSouls = soulmateContract.totalSouls();
      assertTrue(totalSouls == 2);
      }
    • Recommendation:

    • We can add a counter in Soulmate::mintSoulmateToken to count soulmates

      See the suggestion below
      + uint256 private s_soulsCounter;
      function mintSoulmateToken() public returns (uint256) {
      address soulmate = soulmateOf[msg.sender];
      if (soulmate != address(0))
      revert Soulmate__alreadyHaveASoulmate(soulmate);
      + s_soulsCounter++;
      address soulmate1 = idToOwners[nextID][0];
      address soulmate2 = idToOwners[nextID][1];
      if (soulmate1 == address(0)) {
      idToOwners[nextID][0] = msg.sender;
      ownerToId[msg.sender] = nextID;
      emit SoulmateIsWaiting(msg.sender);
      } else if (soulmate2 == address(0)) {
      idToOwners[nextID][1] = msg.sender;
      ownerToId[msg.sender] = nextID;
      soulmateOf[msg.sender] = soulmate1;
      soulmateOf[soulmate1] = msg.sender;
      idToCreationTimestamp[nextID] = block.timestamp;
      emit SoulmateAreReunited(soulmate1, soulmate2, nextID);
      _mint(msg.sender, nextID++);
      }
      return ownerToId[msg.sender];
      }
      function totalSouls() external view returns (uint256) {
      - return nextID * 2;
      + return s_soulsCounter;
      }
Updates

Lead Judging Commences

0xnevi Lead Judge over 1 year ago
Submission Judgement Published
Validated
Assigned finding tags:

finding-self-soulmate

- Given the native anonymous nature of blockchain in general, this issue cannot be avoided unless an explicit whitelist is implemented. Even then we can only confirm soulmates are distinct individuals via kyc. I believe finding a soulmate is intended to be permisionless. - However, even though sufficient (500_000_000e18 in each vault) tokens are minted to claim staking and airdrop rewards, it would take 500_000_000 / 2 combined weeks for airdrop vault to be drained which is not unreasonable given there are [80+ million existing wallets](https://coinweb.com/trends/how-many-crypto-wallets-are-there/). Given there is no option to mint new love tokens, this would actually ruin the functionality of the protocol of finding soulmates and shift the focus to abusing a sybil attack to farming airdrops instead. Assigning medium severity for now but am open for appeals otherwise, since most if not all issues lack indepth analysis of the issue.

Support

FAQs

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