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

Incorrect validation for divorced soulmates in the `Airdrop.sol::claim()` function allows them to claim airdrop tokens

Summary

Incorrect validation check in the Airdrop.sol::claim() function will allow divorced users to claim airdrop tokens.

Vulnerability Details

In the Airdrop.sol::claim() function, the following code block checks the divorce status of soulmate and reverts the transaction if soulmate is divorced:

// No LoveToken for people who don't love their soulmates anymore.
if (soulmateContract.isDivorced()) revert Airdrop__CoupleIsDivorced();

The Soulmate.sol::isDivorced() is implemented as follows:

/// @notice Cancel possibily for 2 lovers to collect LoveToken from the airdrop.
function isDivorced() public view returns (bool) {
@> return divorced[msg.sender];
}

Divorce status is checked for the msg.sender. When checking the divorce status in the Airdrop.sol::claim() function, the divorce status is checked for the Airdrop.sol contract instead of the user wanting to claim airdrop tokens.

Impact

Divorced users are able to claim airdrop tokens.

Proof of Concept (PoC)

Add the following test in AirdropTest.t.sol:

function test_divorcedSoulmatesCanClaimTokens() public {
_mintOneTokenForBothSoulmates();
uint256 airdropVaultBalanceBeforeClaim = loveToken.balanceOf(address(airdropVault));
uint256 divorcedUserBalanceBeforeClaim = loveToken.balanceOf(soulmate1);
assertEq(divorcedUserBalanceBeforeClaim, 0);
vm.warp(block.timestamp + 1 days);
vm.startPrank(soulmate1);
soulmateContract.getDivorced();
assertTrue(soulmateContract.isDivorced());
airdropContract.claim(); // divorced user was allowed to claim airdrop tokens
vm.stopPrank();
uint256 airdropVaultBalanceAfterClaim = loveToken.balanceOf(address(airdropVault));
uint256 divorcedUserBalanceAfterClaim = loveToken.balanceOf(soulmate1);
assertGt(divorcedUserBalanceAfterClaim, divorcedUserBalanceBeforeClaim);
assertEq(airdropVaultBalanceAfterClaim, airdropVaultBalanceBeforeClaim - divorcedUserBalanceAfterClaim);
}

Run a test with forge test --mt test_divorcedSoulmatesCanClaimTokens.

Tools Used

  • Manual review

  • Foundry

Recommendations

Airdrop.sol::claim() should check the divorce status for the user wanting to claim tokens.

Recommended changes to the ISoulmate.sol::isDivorced() function:

-function isDivorced() external view returns (bool);
+function isDivorced(address soulmate) external view returns (bool);

Recommended changes to the Soulmate.sol::isDivorced() function:

-function isDivorced() public view returns (bool) {
+function isDivorced(address soulmate) public view returns (bool) {
- return divorced[msg.sender];
+ return divorced[soulmate];
}

Recommended changes to the Airdrop.sol::claim() function:

function claim() public {
// No LoveToken for people who don't love their soulmates anymore.
- if (soulmateContract.isDivorced()) revert Airdrop__CoupleIsDivorced();
+ if (soulmateContract.isDivorced(msg.sender)) 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
);
}

Add the following test in AirdropTest.t.sol:

function test_claimTokensRevertsWhenSoulmateIsDivorced() public {
_mintOneTokenForBothSoulmates();
uint256 airdropVaultBalanceBeforeClaim = loveToken.balanceOf(address(airdropVault));
uint256 divorcedUserBalanceBeforeClaim = loveToken.balanceOf(soulmate1);
assertEq(divorcedUserBalanceBeforeClaim, 0);
vm.warp(block.timestamp + 1 days);
vm.startPrank(soulmate1);
soulmateContract.getDivorced();
assertTrue(soulmateContract.isDivorced(soulmate1));
vm.expectRevert(Airdrop.Airdrop__CoupleIsDivorced.selector); // divorced user is not allowed to claim airdrop tokens
airdropContract.claim();
vm.stopPrank();
}

Run a test with forge test --mt test_claimTokensRevertsWhenSoulmateIsDivorced.

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.