Abstract Contract vs Interfaces in Solidity

Abstract contracts and interfaces share some similar characterstics but they are different.

Abstract Contracts


  • Contracts need to be marked as abstract when at least one of their functions is not implemented.
  • Contracts may be marked as abstract even though all functions are implemented.
pragma solidity >=0.4.0 <0.7.0;

abstract contract Feline {
    function utterance() public virtual returns (bytes32);
}

  • Such abstract contracts can not be instantiated directly. This is also true, if an abstract contract itself does implement all defined functions.

pragma solidity ^0.6.0;

abstract contract Feline {
    function utterance() public virtual returns (bytes32);
}

contract Cat is Feline {
    function utterance() public override returns (bytes32) { return "miaow"; }
}

  • If a contract inherits from an abstract contract and does not implement all non-implemented functions by overriding, it needs to be marked as abstract as well.

  • Abstract contracts are useful in the same way that defining methods in an interface is useful. It is a way for the designer of the abstract contract to say “any child of mine must implement this method”.

Interfaces


Interfaces are similar to abstract contracts, but they cannot have any functions implemented. There are further restrictions:

  • They cannot inherit from other contracts, but they can inherit from other interfaces.

  • All declared functions must be external in the interface, even if they are public in the contract.

  • They cannot declare a constructor.

  • They cannot declare state variables.

  • They cannot declare modifiers.


// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;

interface Token {
    enum TokenType { Fungible, NonFungible }
    struct Coin { string obverse; string reverse; }
    function transfer(address recipient, uint amount) external;
}
  • Types defined inside interfaces and other contract-like structures can be accessed from other contracts: Token.TokenType or Token.Coin.

  • All functions declared in interfaces are implicitly virtual and any functions that override them do not need the override keyword. This does not automatically mean that an overriding function can be overridden again - this is only possible if the overriding function is marked virtual.

  • Interfaces can inherit from other interfaces. This has the same rules as normal inheritance.


// SPDX-License-Identifier: GPL-3.0
pragma solidity >=0.6.2 <0.9.0;

interface ParentA {
    function test() external returns (uint256);
}

interface ParentB {
    function test() external returns (uint256);
}

interface SubInterface is ParentA, ParentB {
    // Must redefine test in order to assert that the parent
    // meanings are compatible.
    function test() external override(ParentA, ParentB) returns (uint256);
}