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

Users Can Claim `LoveTokens` from `Airdrop` Even After Divorce

Users Can Claim LoveTokens from Airdrop Even After Divorce, Violating the Protocol Rule that Only Couples Can Claim LoveTokens.

Description: In the Airdrop::claim() function, divorced couples can still claim LoveTokens, contrary to the intended design. The issue arises from the following section of the Airdrop::claim() function:

function claim() public {
@> if (soulmateContract.isDivorced()) revert Airdrop__CoupleIsDivorced();
......
}

The problem lies in the forwarded call to the Soulmate contract, where the caller (msg.sender) is the Airdrop contract itself. The Soulmate::isDivorced() function retrieves the value directly for the msg.sender. As the airdrop contract will not have a Soulmate NFT and will never get divorced, if (soulmateContract.isDivorced()) will always be false. Consequently, even after divorce, users will be able to claim airdrop rewards.

Soulmate getDivorced() function

function isDivorced() public view returns (bool) {
@> return divorced[msg.sender];
}

**Impact:**Even after divorce, couples can receive LoveTokens.

Proof of Concept: Here is a proof of code how users can receive love token even after divorced.

Poc for even after divorced user can calim rewards
function test_CanClaimAfterDivorced() public {
_mintOneTokenForBothSoulmates();
// claim BeforeDivorce
vm.startPrank(soulmate1);
bool bresult = soulmateContract.isDivorced();
assert(bresult == false);
vm.stopPrank();
vm.warp(block.timestamp + 1 days + 1 seconds);
vm.prank(soulmate1);
airdropContract.claim();
vm.stopPrank();
vm.prank(soulmate2);
airdropContract.claim();
vm.stopPrank();
vm.prank(soulmate1);
assertTrue(loveToken.balanceOf(soulmate2) == 1 ether);
vm.stopPrank();
vm.prank(soulmate2);
assertTrue(loveToken.balanceOf(soulmate2) == 1 ether);
vm.stopPrank();
//get divorced now
// divorced result
vm.startPrank(soulmate1);
soulmateContract.getDivorced();
bool result = soulmateContract.isDivorced();
assert(result == true);
vm.stopPrank();
vm.warp(block.timestamp + 2 days + 1 seconds);
// claim after divorced
vm.prank(soulmate1);
airdropContract.claim();
vm.stopPrank();
vm.prank(soulmate2);
airdropContract.claim();
vm.stopPrank();
vm.prank(soulmate1);
assertTrue(loveToken.balanceOf(soulmate2) == 3 ether);
vm.stopPrank();
vm.prank(soulmate2);
assertTrue(loveToken.balanceOf(soulmate2) == 3 ether);
vm.stopPrank();
console.log(loveToken.balanceOf(address(airdropVault)));
}

Recommended Mitigation: To address this issue, reorganize the check for divorce at the Soulmate contract by adding the following function:

function checkDivorced(address _caller) public view returns(bool){
return divorced[_caller];
}

Use the above function in the Airdrop::claim() function, passing msg.sender as a parameter:

function claim() public {
- if (soulmateContract.isDivorced()) revert Airdrop__CoupleIsDivorced();
+ if (soulmateContract.checkDivorced(msg.sender)) revert Airdrop__CoupleIsDivorced();
......
}

This modification on both contract ensures protocol rule.

Updates

Lead Judging Commences

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

finding-isDivorced-wrong-check

Support

FAQs

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