medium

HealthTokens can be transferred between users.

Selected Submission

HealthTokens can be transferred between users.

Severity

Medium Risk

Summary

HealthTokens can be transferred between users which breaks invariant.

Details

As stated there should be only two ways to receive HealthToken:

These should be the two eligible ways to receive a HealthToken in this protocol.

setMarketAndVotingAddress: Allows the owner to set the addresses of the MartenitsaMarketplace and MartenitsaVoting contracts.
distributeHealthToken: Allows the marketplace and voting contracts to distribute HealthTokens as rewards to specified addresses.

However, the transfer and transferFrom allow another way to receive HealthTokens.

Proof of Code

paste this test and run it in MartenitsaMarketPlace.t.sol

  function testCanTransferHealthTokens() public {
        address pan = makeAddr("pan");
        //Mint HealthTokens to Bob
        vm.startPrank(bob);
        uint256 i = 0;
        uint256 martenitsaToHealthTokenRatio = 3;
        uint256 amountOfFreeMartenitsaTokens = 99;

        for (i; i < amountOfFreeMartenitsaTokens; i++) {
            martenitsaToken.updateCountMartenitsaTokensOwner(address(bob), "add");
        }
        marketplace.collectReward();

        uint256 bobHealthTokensBalance = healthToken.balanceOf(address(bob));
        uint256 expectedBobHealthTokensBalance = (amountOfFreeMartenitsaTokens / martenitsaToHealthTokenRatio) * 1e18;
        assert(bobHealthTokensBalance == expectedBobHealthTokensBalance);

        healthToken.transfer(pan, bobHealthTokensBalance);
        vm.stopPrank();

        console.log("Pan HealthTokens balance ", healthToken.balanceOf(pan));
        assert(healthToken.balanceOf(pan) == bobHealthTokensBalance);
    }

Tools Used

Manual Review

Unit tests

Recommendations

Override the default ERC20::transfer and ERC20::transferFrom