2

I have a contract that looks like this:

pragma solidity ^0.6.0;
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";

contract SwappableToken is ERC20 {
  constructor(string memory name, string memory symbol, uint initialSupply) public ERC20(name, symbol) {
        _mint(msg.sender, initialSupply);
  }
  function _approve(address owner, address spender, uint256 amount) public override {
        super._approve(owner, spender, amount);
    }
}

However, when doing this I get: TypeError: Overriding function visibility differs.

The _approve method has visibility of internal but I'd like to make it public (Why? Well for testing crazy stuff is all. Yes I know that's a terrible idea for production)

Is it not possible to override the visibility of a function from the base contract?

How would I make an ERC20 where anyone can call the approve function for any owner and sender without rewriting the whole contract?

1 Answer 1

2

The _approve method has visibility of internal

The whole idea of explicit visibility and modifiers like virtual and override is to catch developer errors at compile time. So, you'll be at cross-purposes with the compiler's objectives. You'll end up making functional changes to the thing you're trying to test which is usually a step in the wrong direction.

_approve

The style guide suggests using _ for private and internal function names. Great. There is a corresponding external function, approve() that is not internal. It is part of the ERC20 interface.

Instead of mangling the code for testing purposes, it's usually a good idea to create an accessible function. Something like:

function getPrivateResult() ... {
   return _getPrivateResult();
}

function setPrivateThing(args) ... guards .. {
   _setPrivateThing(args);

The external getPrivateResult() function would be part of the interface (with override) but the interface would be silent on _getPrivateResult().

If you really need a temporary scaffold for testing, consider something like:

function deleteMeTestingOnly(args) ... { // signal auditors this should have been removed
  _approve(args);
}

That pattern helps you keep faith with the idea that the internal state of a contract should be 100% discoverable from the outside. Also, if you look closely, the private function can hold the important logic (once) and there might be multiple routes to it from the outside.

function case1(address user) ... onlyTrustedContract ... {
  _setPrivateThing(user);
}

function case2(address user) ... onlyOwner ... {
  _setPrivateThing(user);

function case3() ... {
  _setPrivateThing(msg.sender);
}

That helps you avoid a tangled mess of concerns like only the owner, or one of my contracts, or one of my users and sometimes pass msg.sender and something get an argument, and ... and ....

The private/internal _setPrivateThing() function would not be part of the defined interface, by definition, but the three cases would be.

Hope it helps.

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.