原文: 《Solidity 極簡入門: 14.抽象合約和接口》

我最近在重新學solidity,鞏固一下細節,也寫一個「Solidity 極簡入門」,供小白們使用(編程大佬可以另找教程),每週更新1-3 講。

所有代碼和教程開源在github: github.com/AmazingAng/WTFSolidity

這一講,我們用ERC721 的接口合約為例介紹solidity 中的抽象合約(abstract)和接口(interface),幫助大家更好的理解ERC721 標準。

抽象合約

如果一個智能合約里至少有一個未實現的函數,即某個函數缺少{} 中的內容,則必須將該合約標為abstract,不然編譯會報錯;另外,未實現的函數需要加virtual,以便子合約重寫。拿我們之前的插入排序合約為例,如果我們還沒想好具體怎麼實現插入排序函數,那麼可以把合約標為abstract,之後讓別人補寫上。

Solidity極簡入門第十四講:抽象合約和接口

接口

接口類似於抽象合約,但它不實現任何功能。接口的規則:

- 不能包含狀態變量

- 不能包含構造函數

- 不能繼承除接口外的其他合約

- 所有函數都必須是external 且不能有函數體

- 繼承接口的合約必須實現接口定義的所有功能

雖然接口不實現任何功能,但它非常重要。接口是智能合約的骨架,定義了合約的功能以及如何觸發它們:如果智能合約實現了某種接口(比如ERC20 或ERC721),其他Dapps 和智能合約就知道如何與它交互。因為接口提供了兩個重要的信息:

- 合約裡每個函數的bytes4 選擇器,以及基於它們的函數簽名函數名(每個參數類型)。

- 接口id(更多信息見EIP165)

另外,接口與合約ABI(Application Binary Interface)等價,可以相互轉換:編譯接口可以得到合約的ABI,利用abi-to-sol 工具也可以將ABI json 文件轉換為接口sol 文件。

我們以ERC721 接口合約IERC721 為例,它定義了3 個event 和9 個function,所有ERC721 標準的NFT 都實現了這些函數。我們可以看到,接口和常規合約的區別在於每個函數都以;代替函數體{ } 結尾。

Solidity極簡入門第十四講:抽象合約和接口

IERC721 事件

IERC721 包含3 個事件,其中Transfer 和Approval 事件在ERC20 中也有。

- Transfer 事件:在轉賬時被釋放,記錄Token的發出地址from,接收地址to 和tokenid。

- Approval 事件:在授權時釋放,記錄授權地址owner,被授權地址approved 和tokenid`。

- ApprovalForAll 事件:在批量授權時釋放,記錄批量授權的發出地址owner,被授權地址operator 和授權與否的approved。

IERC721 函數

balanceOf:返回某地址的NFT 持有量balance。

ownerOf:返回某tokenId 的主人owner。

transferFrom:普通轉賬,參數為轉出地址from,接收地址to 和tokenId。

safeTransferFrom:安全轉賬(如果接收方是合約地址,會要求實現ERC721Receiver 接口)。參數為轉出地址from,接收地址to 和tokenId。

approve:授權另一個地址使用你的NFT。參數為被授權地址approve 和tokenId。

getApproved:查詢tokenId 被批准給了哪個地址。

setApprovalForAll:將自己持有的該系列NFT 批量授權給某個地址operator。

isApprovedForAll:查詢某地址的NFT 是否批量授權給了另一個operator 地址。

safeTransferFrom:安全轉賬的重載函數,參數里麵包含了data。

什麼時候使用接口?

如果我們知道一個合約實現了IERC721 接口,我們不需要知道它具體代碼實現,就可以與它交互。

無聊猿BAYC 屬於ERC721 Token,實現了IERC721 接口的功能。我們不需要知道它的源代碼,只需知道它的合約地址,用IERC721 接口就可以與它交互,比如用balanceOf() 來查詢某個地址的BAYC 餘額,用safeTransferFrom() 來轉賬BAYC。

Solidity極簡入門第十四講:抽象合約和接口

總結

這一講,我介紹了`solidity`中的抽象合約(`abstract`)和接口(`interface`),他們都可以寫模版並且減少代碼冗餘。我們還講了`ERC721`接口合約`IERC721`,以及如何利用它與無聊猿`BAYC`合約進行交互。