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

`Airdrop::claim` checks divorce for `Airdrop` contract instead of caller leads to reward claims even for divorced people.

Summary

The Airdrop contract allows soulmates to claim LoveToken if they are in relation but should not allow divorced people to claim tokens as mentioned by the protocol.
The check inside the Airdrop::claim function checks for divorce condition of Airdrop contract instead of the actual caller leading to airdrop claims even though the soulmates are divorced and as the Airdrop contract will not be in relation therefore the divorce condition will always be false, and thus allowing divorced users to still claim Airdrop as usual when they were not divorced.

Vulnerability Details

The vulnerability lies at line 53 inside Airdrop contract's claim function which represents the incorrect condition for evaluating whether caller is divorced or not.
The call soulmateContract.isDivorced() made inside Airdrop::claim function actually returns the divorce status of Airdrop contract because the caller of isDivorced function on Soulmate contract is Airdrop contract. Thus, it returns the divorce status of Airdrop contract instead of the caller who called the Airdrop::claim function, allowing divorced people to still take benefits of Airdrop.

function claim() public {
// No LoveToken for people who don't love their soulmates anymore.
@> if (soulmateContract.isDivorced()) revert Airdrop__CoupleIsDivorced();
// Calculating since how long soulmates are reunited
uint256 numberOfDaysInCouple = (block.timestamp -
soulmateContract.idToCreationTimestamp(
soulmateContract.ownerToId(msg.sender)
)) / daysInSecond;
uint256 amountAlreadyClaimed = _claimedBy[msg.sender];
if (
amountAlreadyClaimed >=
numberOfDaysInCouple * 10 ** loveToken.decimals()
) revert Airdrop__PreviousTokenAlreadyClaimed();
uint256 tokenAmountToDistribute = (numberOfDaysInCouple *
10 ** loveToken.decimals()) - amountAlreadyClaimed;
// Dust collector
if (
tokenAmountToDistribute >=
loveToken.balanceOf(address(airdropVault))
) {
tokenAmountToDistribute = loveToken.balanceOf(
address(airdropVault)
);
}
_claimedBy[msg.sender] += tokenAmountToDistribute;
emit TokenClaimed(msg.sender, tokenAmountToDistribute);
loveToken.transferFrom(
address(airdropVault),
msg.sender,
tokenAmountToDistribute
);
}

Impact

Divorced users can still claim Airdrop due to the incorrect divorce condition implemented inside Airdrop::claim function.

PoC

Add the test in the file: test/unit/AirdropTest.t.sol

Run the test:

forge test --mt test_DivorcedUserCanStillClaimAirdrop
function test_DivorcedUserCanStillClaimAirdrop() public {
vm.prank(soulmate1);
soulmateContract.mintSoulmateToken();
// 10 days after another soulmate arrives
vm.warp(block.timestamp + 10 days);
vm.prank(soulmate2);
soulmateContract.mintSoulmateToken();
// after two days soulmate1 decides to get divorce
vm.warp(block.timestamp + 2 days);
// soulmate1 feels cheated and gets instant divorce 💔💔
vm.prank(soulmate1);
soulmateContract.getDivorced();
// assert check: both soulmates are now divorced
vm.prank(soulmate1);
assert(soulmateContract.isDivorced() == true);
vm.prank(soulmate2);
assert(soulmateContract.isDivorced() == true);
uint256 balanceBeforeClaim = loveToken.balanceOf(soulmate1);
// call the claim function on Airdrop
// according to the protocol, they should not be able to claim airdrop
vm.prank(soulmate1);
airdropContract.claim();
uint256 claimedBalance = loveToken.balanceOf(soulmate1) - balanceBeforeClaim;
// the balance increases
// this signifies that the user is still able to claim Airdrop even after getting divorce
assert(claimedBalance > 0);
}

Tools Used

Manual Review, Unit Test in Foundry

Recommendations

Instead of checking divorce condition of Airdrop contract, check the same for the caller of Airdrop::claim function.

  • Soulmate contract doesn't have the function to query the divorce condition of a user, therefore implementing the same inside Soulmate contract:

function isDivorced(address user) public view returns (bool) {
return divorced[user];
}
  • Modify the check inside Airdrop::claim function to check divorce condition for the caller (At line 53)

-if (soulmateContract.isDivorced()) revert Airdrop__CoupleIsDivorced();
+if (soulmateContract.isDivorced(msg.sender)) revert Airdrop__CoupleIsDivorced();
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.