1

Have this contract from oz

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/draft-ERC20Permit.sol";
import "@openzeppelin/contracts/token/ERC20/extensions/ERC20Votes.sol";

contract MyToken is ERC20, ERC20Permit, ERC20Votes {
    constructor() ERC20("MyToken", "MTK") ERC20Permit("MyToken") {}

    // The following functions are overrides required by Solidity.

    function _afterTokenTransfer(address from, address to, uint256 amount)
        internal
        override(ERC20, ERC20Votes)
    {
        super._afterTokenTransfer(from, to, amount);
    }

    function _mint(address to, uint256 amount)
        internal
        override(ERC20, ERC20Votes)
    {
        super._mint(to, amount);
    }

    function _burn(address account, uint256 amount)
        internal
        override(ERC20, ERC20Votes)
    {
        super._burn(account, amount);
    }
}

Can someone explain me why exactly we are using super._mint(to, amount)? I see no difference in code execution when I simply not putting it here. Also can't get why specify override(ERC20, ERC20Votes) instead of just override? I thought It will resolve in correct order anyway? Or am I wrong?

2 Answers 2

2
+50

Just expanding on what @Kof said.

This doesn't accomplish anything.

    function _mint(address to, uint256 amount)
        internal
        override(ERC20, ERC20Votes)
    {
        super._mint(to, amount);
    }

It calls the inherited contract (super) and _mint() without changing anything, so it's a replacement internal function that doesn't change anything.

If you check mintable on the wizard page, you'll see:

    function mint(address to, uint256 amount) public onlyOwner {
        _mint(to, amount);
    }

That's a public function, so anyone can call it, but it also adds access control (onlyOwner). Then, it uses the provided internal _mint() function.

Guidance is not always as helpful as one might like. The main takeaway is the internal function has no access control and it's not exposed to the outside. It should only be used by a function you make that knows what it's doing.

Hope it helps.

2
  • so function _burn(address account, uint256 amount) internal override(ERC20, ERC20Votes) { super._burn(account, amount); } can be safely deleted? even thou we have internal virtual in the parent one?
    – Paul
    Jun 29, 2022 at 2:19
  • You don't need that or _afterTokenTransfer(). Same logic. virtual means you can override it, but you're not obliged to. Those internal functions are there to use if you need to. A common pattern is to call _mint() from the constructor so the supply isn't capped at 0. Similarly, if you want your users to be able to burn(), then make a public burn() function that relies on the internal _burn() function. Jun 29, 2022 at 14:52
0

OZ's methods starting with _ are internal both for a clear distinction against external methods.

The _mint doesn't make role checks, etc. it just mints, so it must not be public/external.

You don't need to override these at all, whatever function which mints should just call _mint(...).

You can mint in your constructor, or in a special method that requires a specific amount to be paid, etc.

1

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.