WTF Solidity: 14. Abstract and Interface
Twitter: @0xAA_Science | @WTFAcademy_
Community: Discord|Wechat|Website wtf.academy
Codes and tutorials are open source on GitHub: github.com/AmazingAng/WTFSolidity
In this section, we will introduce the abstract
and interface
contracts in Solidity, using the interface of ERC721
as an example. They are used to write contract templates and reduce code redundancy.
Abstract contract
If a contract contains at least one unimplemented function (no contents in the function body {}
), it must be labeled as abstract
; Otherwise it will not compile. Moreover, the unimplemented function needs to be labeled as virtual
.
Take our previous Insertion Sort Contract as an example,
if we haven't figured out how to implement the insertion sort function, we can mark the contract as abstract
, and let others overwrite it in the future.
abstract contract InsertionSort{
function insertionSort(uint[] memory a) public pure virtual returns(uint[] memory);
}
Interface
The interface
contract is similar to the abstract
contract, but it requires no functions are implemented. Rules of the interface:
- Cannot contain state variables.
- Cannot contain constructors.
- Cannot inherit non-interface contracts.
- All functions must be external and cannot have contents in the function body.
- The contract that inherits the interface contract must implement all the functions defined in it.
Although the interface does not implement any functionality, it is the skeleton of smart contracts. Interface
defines what the contract does and how to interact with them: if a smart contract implements an interface (like ERC20
or ERC721
),
other Dapps and smart contracts will know how to interact with it. Because it provides two important pieces of information:
- The
bytes4
selector for each function in the contract, and the function signaturesfunction name (parameter type)
. - Interface id (see EIP165 for more information)
In addition, the interface is equivalent to the contract ABI
(Application Binary Interface),
and they can be converted to each other: compiling the interface contract will give you the contract ABI
,
and [abi-to-sol tool](https://gnidan.github.io/ abi-to-sol/) will convert the ABI
back to the interface contract.
We take IERC721
contract, the interface for the ERC721
token standard, as an example. It consists of 3 events and 9 functions,
which all ERC721
contracts need to implement. In interface, each function ends with ;
instead of the function body { }
. Moreover, every function in interface contract is by default virtual
, so you do not need to label function as virtual
explicitly.
interface IERC721 is IERC165 {
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
function balanceOf(address owner) external view returns (uint256 balance);
function ownerOf(uint256 tokenId) external view returns (address owner);
function safeTransferFrom(address from, address to, uint256 tokenId) external;
function transferFrom(address from, address to, uint256 tokenId) external;
function approve(address to, uint256 tokenId) external;
function getApproved(uint256 tokenId) external view returns (address operator);
function setApprovalForAll(address operator, bool _approved) external;
function isApprovedForAll(address owner, address operator) external view returns (bool);
function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data) external;
}
IERC721 Event
IERC721
contains 3 events.
Transfer
event: emitted during transfer, records the sending addressfrom
, the receiving addressto
, andtokenid
.Approval
event: emitted during approval, records the token owner addressowner
, the approved addressapproved
, andtokenid
.ApprovalForAll
event: emitted during batch approval, records the owner addressowner
of batch approval, the approved addressoperator
, and whether the approve is enabled or disabledapproved
.
IERC721 Function
IERC721
contains 3 events.
balanceOf
: Count all NFTs held by an owner.ownerOf
: Find the owner of an NFT (tokenId
).transferFrom
: Transfer ownership of an NFT withtokenId
fromfrom
toto
.safeTransferFrom
: Transfer ownership of an NFT withtokenId
fromfrom
toto
. Extra check: if the receiver is a contract address, it will be required to implement theERC721Receiver
interface.approve
: Enable or disable another address to manage your NFT.getApproved
: Get the approved address for a single NFT.setApprovalForAll
: Enable or disable approval for a third party to manage all your NFTs in this contract.isApprovedForAll
: Query if an address is an authorized operator for another address.safeTransferFrom
: Overloaded function for safe transfer, containingdata
in its parameters.
When to use an interface?
If we know that a contract implements the IERC721
interface, we can interact with it without knowing its detailed implementation.
The Bored Ape Yacht Club BAYC
is an ERC721
NFT, which implements all functions in the IERC721
interface. We can interact with the BAYC
contract with the IERC721
interface and its contract address, without knowing its source code.
For example, we can use balanceOf()
to query the BAYC
balance of an address, or use safeTransferFrom()
to transfer a BAYC
NFT.
contract interactBAYC {
// Use BAYC address to create interface contract variables (ETH Mainnet)
IERC721 BAYC = IERC721(0xBC4CA0EdA7647A8aB7C2061c2E118A18a936f13D);
// Call BAYC's balanceOf() to query the open interest through the interface
function balanceOfBAYC(address owner) external view returns (uint256 balance){
return BAYC.balanceOf(owner);
}
// Safe transfer by calling BAYC's safeTransferFrom() through the interface
function safeTransferFromBAYC(address from, address to, uint256 tokenId) external{
BAYC.safeTransferFrom(from, to, tokenId);
}
}
Remix demo
- Abstract example:
- Interface example:
Summary
In this chapter, we introduced the abstract
and interface
contracts in Solidity, which are used to write contract templates and reduce code redundancy.
We also learned the interface of ERC721
token standard and how to interact with the BAYC
contract using interface.