Infinite loop in 'Automating the Reward' code example (?)

Hi all,

Question re 'Automating the Reward' example in ERC20 'Creating supply' section. This code doesn't compile for me, with the compiler saying that there are unreachable lines. Does this code cause an infinite loop since '_mint' triggers the '_beforeTokenTransfer' hook. Is there any workaround for this?

Thanks,
Jonathan

I just noticed there is an '_afterTokenTransfer' hook as well, so I used that to reset a 'minerRewardPaid' boolean variable which I'm using to prevent an infinite loop.

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Capped.sol";

contract MyToken is ERC20Capped, ERC20Burnable {
    bool private minerRewardPaid = false;

    constructor(uint256 cap) ERC20("MyToken", "ICHC") ERC20Capped(cap * (10 ** decimals())) {
        _mint(msg.sender, (cap / 2) * (10 ** decimals()));
    }

    /**
     * @dev See {ERC20Capped-_mint}.
     */
    function _mint(address account, uint256 amount) internal virtual override(ERC20Capped, ERC20) {
        require(ERC20.totalSupply() + amount <= cap(), "ERC20Capped: cap exceeded");
        super._mint(account, amount);
    }

    function _mintMinerReward() internal {
        if (!minerRewardPaid && block.coinbase != address(0)) {
          minerRewardPaid = true;
          _mint(block.coinbase, 10);
        }
    }

    function _beforeTokenTransfer(address from, address to, uint256 value) internal virtual override {
        _mintMinerReward();
        super._beforeTokenTransfer(from, to, value);
    }

    function _afterTokenTransfer(address from, address to, uint256 value) internal virtual override {
        minerRewardPaid = false;
        super._afterTokenTransfer(from, to, value);
    }
}

Good point, I've published a fixed snippet:

    function _beforeTokenTransfer(address from, address to, uint256 value) internal virtual override {
        if (!(from == address(0) && to == block.coinbase)) {
          _mintMinerReward();
        }
        super._beforeTokenTransfer(from, to, value);
    }

Awesome, I like the approach - thanks.

Just one small suggestion - this code resulted in minting to a zero address in the test env. I've added one more check to prevent minting to zero address. I'm sure there's a more concise way to write this, but seems to work for me:

function _beforeTokenTransfer(address from, address to, uint256 value) internal virtual override {
        if (from != address(0) && to != block.coinbase && block.coinbase != address(0)) {
          _mintMinerReward();
        }
        super._beforeTokenTransfer(from, to, value);
    }

That is an interesting error. I think I'm going to leave it as is for simplicity of the material.