Summary
The Airdrop contract allows users who already divorced to claim tokens, which should not be possible.
Vulnerability Details
The soulmateContract.isDivorced() function is incorrectly implemented, in a way that always returns false, so the claim() function allows to continue receiving love tokens after divorce.
isDivorced() should receive the address of the user to check, but instead it gets msg.sender, which is the address of the Airdrop contract.
This test calls claim() after divorce.
function testClaimAfterGetDivorced() public {
_mintOneTokenForBothSoulmates();
uint256 _days = 100;
vm.warp(block.timestamp + (_days * 1 days));
vm.startPrank(soulmate1);
soulmateContract.getDivorced();
airdropContract.claim();
console2.log("balance", loveToken.balanceOf(soulmate1));
}
The test shows the tokens sent to alice.
Running 1 test for test/unit/AuditTest1.t.sol:AuditTest1
[PASS] testClaimAfterGetDivorced() (gas: 333280)
Logs:
balance 100000000000000000000
Impact
Divorced soulmates can steal tokens from the airdrop vault.
Tools Used
Foundry, Manual review
Recommendations
Fix isDivorced() call in Airdrop:claim()
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];
Fix interface in ISoulmate.sol
-function isDivorced() external view returns (bool);
+function isDivorced(address) external view returns (bool);
Fix Soulmate:isDivorced() to pass the address to check
-function isDivorced() public view returns (bool) {
- return divorced[msg.sender];
+function isDivorced(address soulmate) public view returns (bool) {
+ return divorced[soulmate];
}