6

Can an interface enforce a modifier on a function?

For example, does this work:

contract TokenSeller {

  modifer enforceSale(uint256 amount) {
    ERC20 t = token();
    uint256 beforeBalance = t.balanceOf(msg.sender);
    _;
    uint256 afterBalance = t.balanceOf(msg.sender);
    require(afterBalance == beforeBalance + amount);
  }

  function buyToken(uint256 amount) public enforceSale(amount) returns(uint256);

  function token() public returns(ERC20);
}

Is there another way to achieve this kind of interface?

2 Answers 2

7

SHORT ANSWER

No, maybe with abstract contracts you can achieve something similar

LONG ANSWER

First of all to create an interface the keyword interface should be used (I used version 0.4.24 of solidity and the solidity documentation. I played a little bit with your code and when you try to create a function in an interface with a modifier, like this:

pragma solidity ^0.4.24;

interface A {
    modifier onlyOwner() {
        require(getOwner() == msg.sender);
        _;
    }
    function getOwner() public returns(address);
    function updateState() public onlyOwner();
 }

You'd receive this warning: enter image description here

Therefore, apparently, you cannot enforce a modifier in an interface.

Maybe you can try with an abstract contract and the template method pattern:

contract A {

    modifier onlyOwner() {
        require(getOwner() == msg.sender);
        _;
    }
    // The internal keyword let function be visible only to the contract itself and the derivatives
    function getOwner() internal returns(address);  

    function performOperation() internal; // The real operation

    function updateState() public onlyOwner() {
        performOperation();
    }

}

So when you create a concrete subcontract can specify the "performOperation" function:

contract B is A {
    address private owner;
    uint state;
    constructor() public {
        owner = msg.sender;
        state = 0;
    }
    function getOwner() internal returns(address) {
        return owner;
    }
    function performOperation() internal {
        state = state + 1;
    }
}

Obviously with abstract classes you can also avoid the function getOwner in this way:

    contract A {
        address internal owner;

        constructor() internal {
           owner = msg.sender;
        }
        modifier onlyOwner() {
            require(owner == msg.sender);
            _;
        }
        function performOperation() internal;
        function updateState() public onlyOwner() {
            performOperation();
        }
    }

and so you can instantiate a subcontract with already the owner variable :

contract B is A {
    uint state;
    //Call A's constructor before B's one
    constructor() A() public { state = 0; }
    function performOperation() internal { state = state + 1; }
}

P.S. Did you try your code on remix https://remix.ethereum.org ?

1

What you can do is to use a virtual contract as an "interface" (as suggested above). The scheme is:

abstract contract A {
    modifier adminOnly {
    /// checks admin
    _;
    }
    function f() external adminOnly returns (uint){
      return __f__(); 
    }
    function __f__() virtual internal returns (uint);
}

contract B is A {
     function __f__() internal override returns (uint) {
     // whatever you do here has modifier applied before
     }
}

and now you can only override __f__ is subsequent contract that would inherit from A and thus you enforce the modifier

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.