我們先來假想一個情境:你去便利商店買可樂,假設可樂一瓶售價 20 元,如果你身上只有 10 元,就算旁邊的朋友多湊了 9 元給你,以 19 元的現金支付能力,你還是買不到可樂的。你的支付能力必須大於等於 20 元,才能從商店帶走一瓶可樂。再者,如果你拿 100 元的鈔票給店員,店員在交給你可樂的時候,還必須退還給你扣除可樂本身售價後的 80 元。
你可以發現這個交易模式本身就含有一套規則,並且含有一些檢核機制──檢查你的支付能力是否大於等於商品的售價。這個檢查機制對於「購買一罐可樂」來說是足夠的,如果把可樂換成菸酒,這個檢核機制可能還得再增加一些步驟,像是檢查客戶是否達到可購買菸酒的法定年齡。
從資訊化的角度來看,如果一個系統的運作機制總是單純且固定的,例如買飲料這件事,它就容易被程式化(自動化)。事實上在你的生活中就有一種機器很擅長做這件事──自動販賣機。
如果我們觀察自動販賣機的金流,首先它會接收使用者投入的錢幣,接著檢查投入的金額是否足額購買所選擇的商品,最後將商品投放給使用者後,會再檢查是否需要找零。這一切的運作機制都跟你去便利商店買飲料一模一樣,而這些交易邏輯,都被製造商轉譯為程式碼,並且燒錄在自動販賣機的硬體晶片中,使機器一上電就能一直運作同樣的邏輯。
Nick Szabo 在 1994 年首次提出「智能合約」概念時,就提到了自動販賣機的例子[1]。自動販賣機裡那段「處理交易機制的程式邏輯」,就是一份「合約」的概念──一份關於購買飲料的合約。從資訊的角度來看,你可以說其實智能合約的真面目就是一段程式碼──一段定義交易邏輯的程式碼。
如果你曾經申請過虛擬貨幣的電子錢包,或是在虛擬貨幣交易所擁有帳戶,你應該對虛擬貨幣的地址(Address)有點概念。
虛擬貨幣的地址是由一串英文字母和數字所组成的 16 進位格式字串(以 0x 為開頭)。不同的加密貨幣所規範的地址長度可能會不同,以以太坊(Ethereum)而言,以太坊的地址的長度是 42 個字元,例如:
0x5aAadA81BF7eC8F08513d08eaE8bE4DC0ad36c5b
你可以把地址想像成銀行的帳號,只要你在區塊鏈上擁有一個地址(帳戶),意味著你可以接受帳款或轉帳給他人。在虛擬貨幣的世界中,你透過地址將虛擬貨幣發送給他人,或從他人的地址接收虛擬貨幣。
現在我們來想像一件事:假如我想在區塊鏈上運作一個類似 Kickstarter 的眾籌平台。我該怎麼做呢?
我們可以先觀察傳統的眾籌流程是怎麼進行的?有個製造商想製造並販售一件商品,但是他沒有足夠的資金啟動這個計畫,於是製造商在 Kickstarter 上發起一個眾籌計畫。製造商會設定一個眾籌目標,像是需要在一個月內集資超過 100 萬美元,然後開放接受投資人的贊助。
任何對這個計畫有信心的投資人會將金額匯款給 Kickstarter,請注意這裡的金流,Kickstarter 將會持有這筆資金直到募資所設定的截止時間。如果募資達標,Kickstarter 會將所募得的資金扣除手續費後轉給製造商啟動計畫;如果沒有達標,Kickstarter 會將贊助款退回給投資者。你可以發現在這樣的模式中,眾籌平台扮演著中間人的角色,投資人的贊助金將匯入眾籌平台,眾籌平台再根據眾籌結果轉出給製造商或是退還給投資人。
有了剛剛自動販賣機的經驗,你應該馬上可以想到一件事:如果眾籌需要處理的事情都很固定,那它就可以被程式化,被轉換成一種專門處理眾籌的智能合約。
為什麼智能合約能做到這件事情呢?因為當智能合約部署到區塊鏈上,合約本身將會被分配到一個地址。與先前提到的概念一樣,只要在鏈上擁有地址(帳戶)就能接受帳款或轉帳給他人,這意味著「可以把虛擬貨幣轉入合約的地址裡」。當智能合約可以乘載貨幣,可以操作資金的轉入及轉出時,就代表著任何人都可以在區塊鏈上創造一個數位資產代理人。這同時也說明智能合約的出現挑戰了所有具備代理性質的交易,例如保險就是其中之一。
回到我們的眾籌例子,製造商可以撰寫一份屬於自己的眾籌合約,將合約部署在區塊鏈上。贊助者將贊助金匯入合約的地址,由合約程式碼持有這些資金,直到合約所設定的眾籌時間截止。接著合約程式碼會檢查是否達到集資目標,如果募資成功,合約程式碼能自動將資金轉給製造商啟動計畫;如果募資失敗,合約程式碼也會自動將款項退回到各個投資者的帳戶中。在這個過程中不會有真實世界的中介者存在,合約本身就扮演了中介者的角色。
你可能會覺得這個過程有一件事情令人擔心:贊助者憑什麼要信任這份由製造商撰寫的智能合約?當贊助者和製造商使用眾籌平台提供的服務時,表示他們都信任身為中間人的眾籌平台能妥善處理金流。而在區塊鏈中,智能合約要得到同等的信任基礎,是透過兩種特性做到的。
首先,智能合約因為部署在區塊鏈上,這使得交易記錄具備分散式(Distributed)的特性。區塊鏈上的所有交易,都會在散佈於世界各地的運算單元(通常是電腦主機或是礦機)中留下副本。當一個運算單元處理了一筆交易,就會將交易結果同步到鏈上的其它運算單元中。這使得任何參與集資的個人,無法在眾籌截止日之前聲稱眾籌已結束,要求合約提早釋出資金。當這樣的交易需求一送到鏈上,這個全世界最大的分散式網路會檢查並發現這個錯誤,捨棄這個交易需求。精確地說,這個特性與智能合約無關,而是區塊鏈的原生特性。
另一個重要的特性是:智能合約一旦部署到區塊鏈上,就無法再被篡改(Immutable)。但請小心這件事情所代表的真實意義。智能合約的本質是一段處理交易邏輯的程式碼。當我們說「合約部署後無法再被篡改」,指的是「程式碼的原始運作機制」無法被重新編輯。但是撰寫合約的人是可以透過精心設計的程式碼改變某些商業規則設定的。舉個例子,假如有一份智能合約表明若獲利超過一定的比例,將返利 2% 給所有贊助者。這個 2% 的條件如果在程式碼中,被設計為一個可以由外部更改的變數時,就表示 2% 的這個條件是可以被更改的,既使程式碼本身不會被更動。因此檢視合約的程式碼以確保其符合約定條款對投資人來說是很重要的。一般來說,合約代表著一種共識,智能合約是透過允許所有參與者驗證合約條款來實現信任的。
Immutable 所衍伸的另一個問題是:如果合約程式碼被發現有 Bug(程式錯誤)或是效能低落,那個合約就永遠會保持那個錯誤或效能低的狀態。一旦發生這種事情,合約的建立者只能選擇重新部署一份正確的新合約,並且告知用戶不要繼續使用舊合約。
現在你應該知道,智能合約真面目,就是一支「對你的數位資產有直接操作權的程式碼」。大部分的交易程式碼不外乎就是做條件檢查,然後根據檢查結果做出反應。在程式設計中可視為典型「if this then that」的機制。根據這個邏輯,我們可以讓智能合約做一些有趣的事情:
if「有人轉 5 個 A 代幣給我」then「我轉 20 個 B 代幣給他」。
if「我的智能合約裡的贊助金額達到 5 個以太幣」then「所有贊助者都能獲得我所發行的 NFT」。
if「你持有我所發行的特殊代幣」then「你能夠有權限進入某個特殊的社群或讀書會」。
甚至是設計一個農作物保險機制:if「農夫所在的鄉鎮區連續 72 小時出現 3 度以下的低溫」then「農夫將可以獲得農損理賠」。
那麼,合約是怎麼知道農夫所在的鄉鎮區是否發生寒害呢?
從程式設計的角度來看,你當然可以在合約程式碼中設計一個特殊功能的函數(function),讓合約的使用者透過外部函數呼叫來輸入氣溫,但真正的問題是──該由誰輸入?是任何一個合約使用者嗎?還是投票表決出來的人選呢?這些作法似乎都不太對勁,不太去中心化。
你可以從這個例子發現智能合約面臨的挑戰,或者精確地說,是區塊鏈的限制。由於區塊鏈是一個封閉的系統,這使得合約程式碼只能獲取鏈上的資料,而無法獲取鏈外真實世界的資訊。
智能合約的本質是設計好觸發條件的程式碼,在前面所舉的例子中,像是「有人轉 5 個 A 代幣給我」、「贊助金額達到 5 個以太幣」,這些觸發條件都是從鏈上可以取得的資訊,但是當合約的觸發條件是來自區塊鏈外的資訊時,例如天氣、或是房屋到底有沒有遭遇火災或是地震,區塊鏈是無法自行搜尋並擷取這些資訊的。解決的辦法就是依靠可信賴的第三方來提供資料。這個提供資料的服務被稱為 Oracle(中譯:預言機)。Oracle 為智能合約提供了一個重要的服務:把鏈外的真實資訊帶進合約中[2]。
我不會在這篇文章中著墨太多關於 Oracle 的事情,但你應該可以想像得到,在一個去中心化的網路環境中,當智能合約需要提取真實世界的資料時,不能只從單一來源獲取資料,也就是說合約應該向「一群 Oracle」或者說是從一個 Oracle Network 中獲取資料,而目前 Chainlink[3] 網路就是在提供這樣的服務,有興趣的可以關注他們的發展。
首先你需要知道的是,不是每一種區塊鏈都支援智能合約。每個鏈所支援的智能合約也不相同。所以通常第一步就是選擇一條區塊鏈。以目前來說,如果你沒有特殊的需求,Ethereum(以太坊)是個好選擇,它畢竟是目前最流行的加密貨幣之一。
在 Ethereum 上你還可以選擇兩種智能合約程式語言:Solidity 以及 Vyper。以目前來說,Solidity 是最受歡迎的智能合約語言,也相對容易找到學習資源。
決定好鏈與程式語言後,你需要建構一個開發及測試環境。Remix[4] 是一個非常推薦入門者使用的整合開發環境(IDE)。在學習撰寫智能合約時,除了編寫程式碼,你還需要編譯程式碼產生 ByteCode,並且將 ByteCode 部署到測試鏈上。上述的這些事情你都可以在 Remix 所提供的 Web IDE 中做到。你需要做的事情只有打開瀏覽器,不需要安裝任何軟體。
與學習任何程式語言一樣,官方文件[5] 永遠都是你需要隨時參考的重要文件。Solidity 進版的速度非常快,在學習時要隨時注意版本的演進,每次進版後的重要更動都會記錄在「Breaking Changes」的章節裡。當你在網路上閱讀教學文件時,也需要注意範例所使用的版本,盡量使用較新的版本。
CryptoZombies[6] 是一個有趣的學習網站,它提供了線上互動的介面,你可以透過製作一個殭屍遊戲來學習如何編寫 Solidity。
Nick Szabo. Smart contracts: Building blocks for digital markets. EXTROPY: The Journal of Transhumanist Thought, (16), 1996 ↩︎
Blockchain oracle. https://en.wikipedia.org/wiki/Blockchain_oracle ↩︎
Chainlink. https://chain.link/ ↩︎
Remix IDE. https://remix.ethereum.org ↩︎
Solidity Documentation. https://docs.soliditylang.org ↩︎
CryptoZombies. https://cryptozombies.io ↩︎