Medium Risk
HealthTokens can be transferred between users which breaks invariant.
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.
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);
}
Manual Review
Unit tests
Override the default ERC20::transfer
and ERC20::transferFrom