1

I'm inheriting 2 abstract contracts having the same function name but slightly different signature.

These are the 2 base contracts:

abstract contract Base1 {
    function foo() internal view virtual returns (address) {
        return msg.sender;
    }
}

abstract contract Base2 {
    function foo() internal override virtual view returns (address payable ret) {
         return msg.sender;
    } 
}

My contract inherits from both of them and attempts to override the foo() method. Here, I will get an error because their signature is slightly different:

contract MyContract is Base1, Base2 {
    // This is going to have an error DeclarationError: Function with same name and parameter types defined twice.
    function foo() internal view override(Base1, Base2) returns (address payable) {
         return msg.sender;
    }
}

The above overriding will throw this error when compiled:

DeclarationError: Function with same name and parameter types defined twice.

How do I override in such a case where the inherited contracts from external packages that I don't have control over have the same methods in them but slightly different signatures?

1

It's not possible by design because address and address payable are different types and one is not implicitly convertible to the other (on purpose).

But it's easy to deal with. Just make your function return address as well and have the caller convert it to address payable.

The other functions that are out of your control and already call foo() are expecting a non-payable address so it's not a problem if they treat your address as such.

And your own functions that know they are dealing with your own contract and that it actually returns a payable address can convert the value to address payable. Alternatively you could add a helper that returns address payable just for them.

4
  • 1
    Thank you! Just wondering, what's the difference between address payable and just address in the returns()? Since payable is mostly to define that a function can be paid, what does the payable do to a returning variable? It's just a returning value and I don't see how it can be "paid" for other than the function itself.
    – xenon
    Aug 15 at 20:56
  • 1
    It's not a modifier for the variable. It's a part of the type name. The type is simply called address payable. You cannot have e.g. uint payable or bytes payable. See docs.soliditylang.org/en/latest/types.html#address. On a plain address you cannot call .transfer() or .send(). You also cannot assign address a variable of address payable type without an explicit conversion. It's just to let you distinguish addresses that can receive either from ones that do not and avoid mixing up the two.
    – cameel
    Aug 16 at 21:28
  • Ahh I get it now. Thank you so much for such great answers and explanations!
    – xenon
    Aug 16 at 21:33
  • Oh, I think I see where the confusion comes from. The issue I linked to was actually about payable on functions, which is a related concept but different and I see that I misremembered that discussion. In your case the issue is simply that these two types are difference and you cannot change type when you are overriding. I'll remove that part from the answer.
    – cameel
    Aug 16 at 21:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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