KryptoCamp — Day27 — solidity — 8
今天看能不能把 solidity 相關的基礎語法全數了解完,至少做到全部看過一遍,未來在看程式碼時或許會比較順利些。
以下內容很多參考自 all in one solidity ,想知道更詳細的內容請購買書籍參閱。
繼承
A is B, C, D
表現 A 先繼承 B 再繼承 C 再繼承 D,D 是末端合約。
solidity 的繼承使用C3線性化的演算法,是一個用於計算解析順序的演算法詳細可參考這裡。
這段程式碼如果 call contract A 的 getInt() function 的話,會回傳的是 C 定義的值,也就是 1。
繼承的合約可以使用所有父合約的非私有 function 及參數。
Modifier
用於針對 function 做補足內容,或是用來檢查執行條件,對於程式碼整理很有幫助,可以把能夠複用的部分寫成 modifier,降低閱讀程式碼的成本。
modifier 可以有參數,也可以選擇在 function 開始時執行或是結束時執行。
函數覆寫
virtual
: 當一個父合約的函數、modifier
或狀態變數被宣告virtual
時,表示他在之後繼承的合約中可以被改變(覆寫)。override
: 當一個子合約的函數、modifier
或狀態變數被宣告override
時,表示他正在改變(覆寫)父合約的函數。
函數的可視性為 private
時不能宣告 virtual
。
多型
主要分為兩個部分,分別是合約的多型以及函數的多型。
同一合約複數同名 function ,藉由帶入的參數決定執行哪個 function 的內容,此為函數多型的表現。
不同合約的同名 function,藉由繼承關係來決定執行哪個 function 的內容,此為合約多型的表現。
關於多型可以參考以下文章:
super 與呼叫父合約的 function
當一個合約部署時,不管你繼承了多少個合約,其實都只會包成一個合約部署出去,所有繼承的父合約程式碼都被包成一個編譯完的結果部署出去。
super
這個關鍵字會調用你定義在這個合約裡面的根合約的函數,如果調用 foo
會得到 B 的 getInt()
也就是 2,調用 boo
的話則會得到 C 的 getInt()
也就是 1 。
Interface
所謂的 interface 其實就像是一個你與對方約定好實作的接口,是一種協議的表現方式,假設今天你在合約當中看到了 interface 裡面有 foo
跟 boo
兩個 function ,可以認為在接下來的合約當中,你必須要讓合約有辦法應付這兩種訊息,否則合約將很有可能失去某些功能或甚至是失效。
看到 interface 卻不實作就很像看到說明書跟你說這邊要鎖螺絲你卻不鎖是一樣的。
- Interface 的函數不可以有實作部分,也不能繼承其他合約、Interface
- Interface 中函數的可視性只能是 external
- Interface 不可有 constructor
- Interface 不可有任何 state variables
- Interface 可以有像是 enum 或 structs 的資料結構,並且用 <interface>.<data structures> 的方式訪問
抽象合約
抽象合約為一個不完全實作的合約,如果合約中有任何一個函數沒有被實作,則它為抽象合約,像是下方程式碼的 contract A 一樣,所有繼承他的合約都必須實作 getInt()
function,否則繼承他的合約也應該標記為 absract
合約。
Import 與 library
藉由 import 關鍵字可以將其他檔案的內容引入到目標檔案裡面。
import 可以藉由 local 的資料夾結構來使用:
也可以直接抓 url 的值:
library 與合約很接近,有兩種類型:
- deployed:有自己的合約地址,可以被智能合約在執行時調用
- embedded:當所有的 library 函數皆為 internal;沒有自己的合約地址,會變成我們合約的一部分程式碼。
這段程式碼 add
與 add2
會回傳相同的結果, using
關鍵字就像是讓後面 for
的資料類型可以 call library 的 function,就像是 extand 的感覺。
比特與以太社群名詞解釋
BIP (Bitcoin Improvement Proposal)
比特幣改進建議,為一項用於介紹和著名比特幣各項協議、資訊、特色、改進想法、意義和技術內容的文件。任何人都可以在任何地方提出新的討論,在爭取到社區的支持以後以BIP模板的方式提交給核心開發者,最後便可透過多重步驟拍板通過(或遭到否決)。
EIP (Ethereum Improvement Proposal)
是由任何人發佈在以太坊開源區的建議提案。EIP 和 BIP 一樣可以是各種技術或想法的改進,比如說 ERC、協議改進、開發工具、新特性等等。
ERC (Ethereum Request for Comments)
是將開發規則統一為標準的提案。在提出 EIP 建議後,待接受認可後官方會發出相應的 ERC 進行一些細節和問題討論,通常情況下此時 EIP 及 ERC 使用相同編號。
ERC 和 EIP 後面伴隨的數字是依照提案提出的先後順序,沒有特殊意義,如 ERC20 是指第 20 個提出的。官方認可的 ERC 標準就像是有 ERC20(同質化代幣,FT) 和 ERC721(非同質化代幣,NFT)等,均為以太坊上代幣種類標準的規範。
ERC-20
ERC-20 為目前以太坊上最多人使用的標準,此標準除了提高 Token 的互換性,還能在 Dapp 上面進行同樣的運行。ERC-20 包含六個功能函式、兩個事件以及三個 Token 資訊的函式。
- totalSupply() → uint256 :回傳總流通的 token 數量。
- balanceOf(address account) → uint256:回傳某地址擁有的 token 數量。
- allowance(address owner, address spender) → uint256 :回傳 owner 允許 spender 消耗的 token 值,預設為 0。當呼叫
approve
時這個值會變動。 - approve(address spender, uint256 amount) → bool :回傳是否成功的布林值,增加調用者針對 spender 所允許的 token 使用。
- transferFrom(address sender, address recipient, uint256 amount) → bool :將
amount
從被允許的 allowance 帳戶sender
轉往recipient
,將會變更allowance
的值。 - transfer(address recipient, uint256 amount) → bool :回傳是否成功的布林值,將
amount
從調用者身上轉往recipient
。
ERC-721
ERC-721 就等於大家常提到的 NFT。所有的 NFTs 都會擁有一個 uint256 也就是 256 位元的代號,也就是 tokenId 所以在每個 ERC-721 的合約之中, 每組 contract address 的每個 uint256 tokenId 都是獨一無二的,這種代幣可以通過區塊鏈上的智能合約追蹤,從而形塑數位化的資產。
ERC-721 的方法有些與 ERC-20 同名,但是實作稍有不同,同時也多了幾個在 ERC-20 沒有的功能。
- balanceOf(address owner) → uint256 balance :回傳
owner
有幾個該合約裡的 token。 - ownerOf(uint256 tokenId) → address owner :回傳擁有某個
tokenId
的address。 - safeTransferFrom(address from, address to, uint256 tokenId) :將
tokenId
從from
地址傳送到to
。 - transferFrom(address from, address to, uint256 tokenId) :與 safeTransferFrom 大致相同,不建議使用這個。
- approve(address to, uint256 tokenId) : 允許
tokenId
轉到to
的 function,邏輯在這裡。 - getApproved(uint256 tokenId) → address operator :回傳
tokenId
允許轉入的 address。 - setApprovalForAll(address operator, bool _approved) :允許
operator
動用所有調用者的 token,或是切換成不允許。 - isApprovedForAll(address owner, address operator) → bool :回傳某個
owner
是不是允許某個operator
操作他所有 token。 - safeTransferFrom(address from, address to, uint256 tokenId, bytes data) :與 safeTransferFrom 相同,只是多接收一個
data
參數,三個參數的 safeTransferFrom 最後也會呼叫到這個 function,詳細看這裡。
可以看到在這上面完全沒有任何關於圖片的資訊,也就是說圖片的儲存並不在原本 ERC-721 的標準使用範圍內,那麼目前許多主流的 NFT 都是怎麼做的呢?
首先 NFT 很多都會有大量的特徵,這些特徵幾乎都會用 metadata 的形式寫在某個地方,而圖片大部分的時候都會定義一個 tokenURI
的 function 並在裡面實作有關圖片的位置,詳細的實作細節可以參考我的另一篇關於 NFT 實作的文章。
ERC-1155
作為一個半同質性代幣(Semi-Fungiable Token)標準問世,同時有別於ERC-721代幣的MetaData是固定的,每個ERC-1155代幣都可以擁有自己格式的MetaData,還提供了批量轉帳、批量查額、批量授權等功能,藉此增加了發行方想要達到的彈性。
標準的 ERC-1155 最少需實現了以下功能:
- balanceOf(address account, uint256 id) → uint256 :回傳
owner
有幾個該合約裡的 token。 - balanceOfBatch(address[] accounts, uint256[] ids) → uint256[] :回傳很多個
account
的對應ids
有多少個。 - setApprovalForAll(address operator, bool approved) : 與 ERC-721 的同名 function 功能相同。
- isApprovedForAll(address account, address operator) → bool :與 ERC-721 同名 function 功能相同。
- safeTransferFrom(address from, address to, uint256 id, uint256 amount, bytes data) :與 ERC-721 同名 function 功能相同。
- safeBatchTransferFrom(address from, address to, uint256[] ids, uint256[] amounts, bytes data) : 與 safeTransferFrom 功能相同,只是可以一次大量轉移。
值得一提的是為什麼 ERC-1155 的 balanceOf
會需要帶入 id
才有辦法查找呢,原因是在同一個合約內可能有多個不同的 token ,因此需要將 _balances
依照 id 切開來分開存放,詳細邏輯可以參考這裡。