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

Inaccurate Divorce Status Check in Airdrop Claim Function

Summary

The claim function in the Airdrop contract presents a vulnerability wherein divorced individuals can erroneously claim rewards. This vulnerability stems from the function's failure to accurately verify the divorce status of the associated soulmate. Consequently, divorced users can exploit this flaw to claim rewards intended for non-divorced soulmates.

Vulnerability Details

In the claim function, the line:

if (soulmateContract.isDivorced()) revert Airdrop__CoupleIsDivorced();
This line checks if the caller's address (msg.sender) is divorced according to the Soulmate contract. However, the isDivorced() function in the Soulmate contract does not take any arguments, and it always checks the divorce status for msg.sender.

Since msg.sender in the Airdrop contract is the address that is calling the claim function, not necessarily the soulmate address associated with the claimed NFT, this check does not accurately determine if the soulmate associated with the claimed NFT is divorced.

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
);
}
function testClaimDivorced() public {
address alice = address(0x1);
address bob = address(0x2);
// Alice mints a soulmate token.
vm.startPrank(alice);
uint256 aliceTokenId = soulmateContract.mintSoulmateToken();
vm.stopPrank();
// Bob mints a soulmate token.
vm.startPrank(bob);
uint256 bobTokenId = soulmateContract.mintSoulmateToken();
vm.stopPrank();
// Assert that Alice and Bob are now soulmates.
assertEq(soulmateContract.soulmateOf(alice), bob);
assertEq(soulmateContract.soulmateOf(bob), alice);
// Alice initiates a divorce.
vm.startPrank(alice);
vm.warp(block.timestamp + 200 days + 1 seconds);
soulmateContract.getDivorced();
// Check Alice's divorce status.
bool isDivorced = soulmateContract.isDivorced();
assertTrue(isDivorced, "Alice should be divorced.");
// Expect the claim to fail due to divorce.
bytes4 expectedRevertReason = bytes4(keccak256("Airdrop__CoupleIsDivorced()"));
vm.expectRevert(expectedRevertReason);
// Attempt to claim should fail.
airdropContract.claim();
// Check that Alice did not receive any tokens.
uint256 aliceBalance = loveToken.balanceOf(alice);
assertEq(aliceBalance, 0, "Alice should not have received tokens after divorce");
vm.stopPrank();
}

Impact

The vulnerability poses a significant risk to the fairness and integrity of the reward distribution system. By exploiting this flaw, divorced users can claim rewards illegitimately, leading to unfair allocation and potential financial losses.

Tools Used

Manual Review

Recommendations

Modify the claim function in the Airdrop contract to accurately check the divorce status of the soulmate associated with the claimed NFT.
Here possible fix for this:
add or modify the isDivorced()as:

- function isDivorced() public view returns (bool) {
+ function isDivorced(address soulmate) public view returns (bool) {
- return divorced[msg.sender];
+ return divorced[soulmate];
}
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
);
}
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.