KryptoCamp — Day27 — solidity — 8

Galen-Ting
廢物到工程師的一大步
10 min readMar 14, 2022

今天看能不能把 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 裡面有 fooboo 兩個 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;沒有自己的合約地址,會變成我們合約的一部分程式碼。

這段程式碼 addadd2 會回傳相同的結果, 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) :將 tokenIdfrom 地址傳送到 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 切開來分開存放,詳細邏輯可以參考這裡

--

--

Galen-Ting
廢物到工程師的一大步

學程式不無聊,無聊就不學程式,皮皮的學習好過死死的學習。