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();
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();
vm.startPrank(soulmate1);
soulmateContract.getDivorced();
bool result = soulmateContract.isDivorced();
assert(result == true);
vm.stopPrank();
vm.warp(block.timestamp + 2 days + 1 seconds);
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.