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?

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 ?

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

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