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

Each soulmate can claim `LoveToken` everyday, even after `Soulmate::getDivorced` function is called.

Summary

In protocol's documentation is stated that Soulmate::getDivorce function cancels the possibility for a couple to collect LoveToken. However Airdrop::claim function allows both soulmates to claim love tokens everyday, even if Soulmate::getDivorce function is called by one of them. This leads to direct theft of airdrop vault's balances.

Vulnerability Details

Add the following in the AirdropTest.t.sol file:

function testClaimAfterDivorce() public {
_mintOneTokenForBothSoulmates();
// 1 day passes
vm.warp(block.timestamp + 1 days);
vm.startPrank(soulmate1);
soulmateContract.getDivorced();
assert(soulmateContract.isDivorced());
airdropContract.claim();
vm.stopPrank();
vm.startPrank(soulmate2);
assert(soulmateContract.isDivorced());
airdropContract.claim();
vm.stopPrank();
assertEq(loveToken.balanceOf(soulmate1), 1e18);
assertEq(loveToken.balanceOf(soulmate2), 1e18);
// 2nd day passes, soulmates still can claim
vm.warp(block.timestamp + 1 days);
vm.startPrank(soulmate1);
airdropContract.claim();
vm.stopPrank();
vm.startPrank(soulmate2);
airdropContract.claim();
vm.stopPrank();
assertEq(loveToken.balanceOf(soulmate1), 2e18);
assertEq(loveToken.balanceOf(soulmate2), 2e18);
}

Impact

High: Due to the fact that funds in the vault are directly at risk.

Tools Used

Manual Review, Foundry

Recommendations

To mitigate this exploit there are few changes that are required to be made:

  1. Add an address parameter in Soulmate::isDivorced function:

- function isDivorced() public view returns (bool) {
- return divorced[msg.sender];
}
+ function isDivorced(address soulmate) public view returns (bool) {
+ return divorced[soulmate];
}
  1. Add the requirement in ISoulmate::isDivorced function also:

- function isDivorced() external view returns (bool);
+ function isDivorced(address) external view returns (bool);
  1. Use msg.sender as a parameter for the check in Airdrop::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
);
}
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.