🏠 Home
Beginner
01 — Introduction to Solidity 02 — Setting Up Your Environment 03 — Your First Smart Contract 04 — Data Types & Variables 05 — Functions & Visibility 06 — Control Flow 07 — Arrays & Mappings 08 — Structs & Enums
Intermediate
09 — Events & Logging 10 — Modifiers 11 — Inheritance 12 — Interfaces & Abstract Contracts 13 — Error Handling 14 — Ether & Wei 15 — Payable Functions 16 — msg.sender & msg.value 17 — Storage vs Memory vs Stack
Advanced
18 — Gas Optimization 19 — ERC-20 Tokens 20 — ERC-721 NFT Standard 21 — Contract Security 22 — Reentrancy Attacks 23 — Oracles & Chainlink 24 — Upgradeable Contracts 25 — Deploying to Mainnet
SolidityMaster / Lesson 12
Lesson 12 of 25

Interfaces & Abstract Contracts

Define contract APIs, achieve polymorphism, and write composable code.

Intermediate

Interfaces

An interface is a fully abstract contract — it defines function signatures without implementation. Interfaces enable composability: your contract can interact with any address that implements the interface, without knowing its internal code. Rules: no state variables, no constructors, all functions must be external.
Solidity
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface IERC20 {
    function totalSupply() external view returns (uint256);
    function balanceOf(address account) external view returns (uint256);
    function transfer(address to, uint256 amount) external returns (bool);
    event Transfer(address indexed from, address indexed to, uint256 value);
}

// Use the interface to interact with any ERC-20 token
contract TokenUser {
    IERC20 public token;

    constructor(address tokenAddress) {
        token = IERC20(tokenAddress);
    }

    function myBalance() public view returns (uint256) {
        return token.balanceOf(address(this));
    }
}

Abstract Contracts

Abstract contracts have at least one unimplemented function. They CAN have implementations (unlike interfaces) but cannot be deployed directly — they must be inherited and completed.
Solidity
abstract contract Payment {
    address public owner;

    constructor() { owner = msg.sender; }

    // Abstract — child MUST implement this
    function processPayment(address recipient, uint256 amount)
        public virtual;

    // Concrete — inherited as-is
    function getOwner() public view returns (address) {
        return owner;
    }
}

contract EthPayment is Payment {
    // Must implement the abstract function
    function processPayment(address recipient, uint256 amount)
        public override
    {
        payable(recipient).transfer(amount);
    }
}

Interface-Based DeFi Interaction

Use interfaces to call external DeFi protocols — here's how to interact with Uniswap V2.
Solidity
interface IUniswapV2Router {
    function swapExactTokensForTokens(
        uint amountIn,
        uint amountOutMin,
        address[] calldata path,
        address to,
        uint deadline
    ) external returns (uint[] memory amounts);
}

contract MySwapper {
    IUniswapV2Router router;

    constructor(address _router) {
        router = IUniswapV2Router(_router);
    }

    function swap(
        address tokenIn,
        address tokenOut,
        uint256 amountIn
    ) external {
        address[] memory path = new address[](2);
        path[0] = tokenIn;
        path[1] = tokenOut;

        router.swapExactTokensForTokens(
            amountIn, 0, path, msg.sender, block.timestamp
        );
    }
}