Lesson 12 of 25
Interfaces & Abstract Contracts
Define contract APIs, achieve polymorphism, and write composable code.
IntermediateInterfaces
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
);
}
}