Contract Staking
Function claimRewards()
Do not check for msg.sender
is in Soulmate.ownerToId
mapping before calculating amountToClaim
which leads timeInWeeksSinceLastClaim
equal number of weeks since Jan 01 1970 to block.timestamp
.
This leads that any account without soulmate can claim as much tokens as much weeks since 1970 to block.timestamp
multiplied by userStakes
.
Attacker generates 9 accounts.
For each account call Airdrop.claim()
which lead to withraw 19765 ether to each contract controlled by attacker
For each account call loveToken.approve(address(stakingContract), 19765 ether)
For each account except last call stakingContract.deposit()
with 19765 ether
4. 1. for the last account stakingContract.deposit()
with considering of remaining balance stakingVault
For each contract call stakingContract.claimRewards()
which leads to withdraw all LoveToken
the remainder of the division stakeContractBalance % 2823
minted to stakingVault
to accounts controlled by attacker.
Add this test to StakingTest.t.sol
and run via forge test --mt test_ClaimRewardsWithoutSoulmate()
to see it success.
Output:
Manual review, foundry.
Make the following changes in Staking.claimRewards()
https://github.com/Cyfrin/2024-02-soulmate/blob/b3f9227942ffd5c443ce6bccaa980fea0304c38f/src/Staking.sol#L70C1-L99C6
High severity, as it allows any pending user to claim staking rewards without owning a soulmate NFT by - Obtaining love tokens on secondary markets - Transfer previously accrued love tokens via airdrops/rewards to another account and abusing the `deposit()` function
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.