如何在區塊鏈 (Blockchain) 上使用 Remix 部署智能合約 (Smart Contract)


上文"區塊鏈 (Blockchain) 在供應鏈 (Supply Chain) 與企業資源規劃 (ERP) 系統扮演什麼角色?"提到區塊鏈的智能合約在企業應用上很重要,這篇就來實作一下在區塊鏈 (Blockchain) 上使用 Remix 部署智能合約 (Smart Contract)吧。

智慧型合約概念於1994年由一名身兼電腦科學家及密碼學專家的學者尼克·薩博首次提出,到了2015年乙太坊區塊鏈推出之後,智能合約 (Smart Contract) 才更具體的被使用在區塊鏈上。

比特幣 (BitCoin) 區塊鏈與乙太坊區塊鏈都可以開發智能合約,但是與比特幣智能合約來比較,乙太坊的智能合約被認為較符合圖靈完備 (Turing Completeness)。

意思就是乙太坊的智能合約開發比較完備,完備的意思就是可以開發任何情況的智能合約,至於原因是什麼,你可以參考這篇文章"Turing Completeness and Cryptocurrency"。

區塊鏈上儲存資料比較容易理解,但是智能合約的程式碼為何可以放在區塊鏈? 這些程式碼在哪裡執行? 

乙太坊的智能合約程式碼會將 Bytecode (位元組碼) 及 ABI (Application Binary Interface) 儲存在區塊鏈,然後可以在乙太坊的虛擬機器 (Ethereum Virtual Machine,EVM) 上執行。你可以想像 Bytecode 就是執行檔,ABI 就是外界跟執行檔溝通的介面 (有點像API)。

乙太坊的智能合約開發環境有很多種,其中比較方便使用的就是 Remix IDE

Remix IDE 乙太坊智能合約開發環境 : https://remix.ethereum.org/

使用Solidity開發智能合約,裡面會有三個基本部分 :  合約的版權宣告、開發合約的Solidity版本、合約內容。

合約的版權宣告 : 可以參考這個列表 https://spdx.org/licenses/

為何智能合約需要宣告版權? 因為智能合約就是把程式碼上鏈,因此大家都可以看到你的智能合約,有些會看到原始碼,有些只看到 Bytecode (位元組碼)。不管是原始碼或是位元組碼,其實都算把智能合約公開了,因為位元組碼是可以解譯為原始碼的。

所以你的智能合約就需要宣告版權,讓大家知道可以如何使用。

開發合約的Solidity版本 : 因為Solidity一直在改版,所以需要知道你的智能合約是使用哪個版本寫的,這樣才能順利地在乙太坊虛擬機器 (Ethereum Virtual Machine,EVM) 上執行。

合約內容 : 就是你的合約定義了哪些規則。


例如一個空的智能合約就長這樣 : 

// SPDX-License-Identifier: MIT 

pragma solidity ^0.8.11; 

contract MyContract { 

}



範例一 : 

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.11; //指定編譯器版本
contract addTest{ //合約
   uint result; //全域性變數

   function getResult(uint _a, uint _b) public returns (uint){ //內部函式
      result = _a + _b;
      return (result);
   }
}


關於Solidity的資料型態,可以參考這裡 : https://ithelp.ithome.com.tw/articles/10203495

執行結果就如下畫面 :


範例二 : 

一個簡單的 Hello World 智能合約 HelloWorld.sol 就長這樣 :
 
// SPDX-License-Identifier: MIT 

pragma solidity ^0.8.11; 

contract HelloWorld { 
   string public name; 

   function setName (string memory newName) public { 
     name=newName; 
   } 

   function getGreeting() public view returns (string memory) { 
     return string(abi.encodePacked("Hello, ", name)); 
   } 
}


Hello World 的執行結果就如下畫面 :

在 Compiler 環境中,有三個地方需要知道 : 
第一個是 Compiler 版本,選擇跟你合約內的版本符合即可;
第二個是勾選 Auto Compile ,就不用每次更改 code 需要再去按 Compile;
第三個是 Enable Optimization,這個設定會跟費用有關,當你勾選並輸入1時,會讓部署 (Deploy) 費用較低,但是呼叫 (Call) 費用會較高。如果勾選並輸入 200 或更高時,會讓部署 (Deploy) 費用較高,但是呼叫 (Call) 費用會較低。如果你知道這個合約不會頻繁呼叫,你就可以輸入1讓部署費用降低;如果這個合約會頻繁呼叫,那就輸入200 或更高;如果你不確定,就不用勾選。Enable Optimization 後面的數字,最大值限制是(2^64-1)。




範例三 : 

版本二的 Hello World : 

// SPDX-License-Identifier: MIT

pragma solidity ^0.8.11;

contract HelloWorld {
   string public name;

   constructor (string memory initName) {
     name=initName;
   }

   function setName (string memory newName) public {
     name=newName;
   }

   function getGreeting() public view returns (string memory) {
     return string(abi.encodePacked("Hello, ", name));
   }
}

版本二的 Hello World 上鏈後的資料如下 :

以上兩個版本的 Hello World 差異只有版本二多了一個 Constructor 來設定初始值。具有 Constructor 在鏈上 Verify 時就必須要有 ABI-encoded 資料,在實際運作時,有時ABI-encoded會自動填入,有時候不會,這個尚不知道是否為bug,日後再查。

如果需要轉換 ABI-encoded ,可以參考 : https://abi.hashex.org/

Constructor 也是一種函式 (Function),當智能合約執行時,會先執行 Constructor,有些 Constructor 會帶參數、或是初始值宣告。像版本二的 Hello World 就有 Constructor ,如果對於程式設計沒有概念的話,就把 Constructor 當成智能合約執行時最開頭執行的函式。

範例四 : 

現在來看看一個可以在帳戶間測試轉帳的智能合約 SimpleBank.sol :

// SPDX-License-Identifier: MIT 

pragma solidity ^0.8.11; 

contract SimpleBank {   
   address payable public owner; 

   constructor () {   
     owner = payable(msg.sender);   
   } 

   function sendMoney () public payable {   
   } 

   function sendMoneyTo (uint _amount, address _to) public payable {
     payable(_to).transfer(_amount);   
   } 

   function withdrawMoney(uint _amount) external {   
     require(msg.sender==owner,"Only owner can do this."); 
     payable(msg.sender).transfer(_amount);   
   } 

   function getBalance () external view returns (uint) {   
     return address(this).balance;   
   }

}


Simple Bank 也有 Constructor ,但是只有初始值宣告而沒有帶參數。



SimpleBank 執行後的畫面如下 :




以上的sendMoney就會轉錢到合約錢包,withdrawMoney就會從合約錢包轉錢出來,getBalance就是查詢合約錢包的餘額,而sendMoneyTo就會轉錢到指定的錢包。

在執行上面的轉帳動作,建議使用 Environment 為 Javascript VM,要正式上Testnet再選用Injected Web3,以免每個動作都要浪費你的練習幣。

每個智能合約都會產生 Bytecode 以及 ABI (Application Binary Interface),Bytecode 就是 EVM的執行程式碼,ABI就是JSON格式的介面資料,這些資料都會儲存在智能合約的區塊鏈上。




範例五 :

現在看看如何在Remix下使用ERC-20。
https://www.youtube.com/watch?v=PdNxXGGWJRI


範例六 :

現在看看如何在Remix下使用ERC-20,並且認證你的智能合約。

發行Token的智能合約上鏈後的資料如下 : (使用Flatten整合智能合約檔案)
https://rinkeby.etherscan.io/address/0x6B83F25B4EaebDc7a77661dFCD8132E9dE01e316


以下的影片說明從無到有的建立一個 Solidity 智能合約的過程 (英文)
https://www.youtube.com/watch?v=s9MVkHKV2Vw

這是他的範例原始碼 :
https://gist.github.com/rodgtr1/427a6e0cea78281fb9ad8ea9980bb5a2

參考資料 :
Smart Contract 開發 https://ithelp.ithome.com.tw/users/20092025/ironman/1759
Ethereum 智能合約開發筆記 https://gist.github.com/Ankarrr/561fb3e49bd22847780fb93f0e382f59



[後記] 

在實際操作Remix來撰寫智能合約時,如果沒有把一些基本操作搞清楚,一定會碰到很多問題,以下是幾個需要先熟悉的基本操作。

一、MetaMask 狐狸錢包 https://metamask.io/
(1) 透過助憶詞 (Secret Recovery Phrase) 恢復錢包,在錢包內從哪取得助憶詞?
(2) 透過私鑰 (Private Key) 恢復錢包,從哪取得私鑰? 從哪匯入私鑰?
(3) 了解以上兩種方式恢復錢包的差異。
(4) 如果錢包有不用的錢包位址 (Wallet Address),如何刪除?
(5) 切換不同的錢包位址,並複製錢包位址。
(6) 切換不同的區塊鏈網路。
(7) 從不同的測試網路取得測試幣。
(8) 讓錢包位址連接不同網站,練習connect與disconnect。
(9) 在不同的錢包位址轉帳,並練習如何調整交易費。
(10) 從 https://rinkeby.etherscan.io/ 查看錢包位址的餘額。

二、Remix介面 http://remix.ethereum.org/
(1) 新增一個智能合約檔案/Workspace。
(2) 下載/回復Workspace。
(3) 從外部(Gist/Github)獲得智能合約檔案。
(4) Compile環境設定。
(5) Deploy環境設定。

三、區塊鏈測試鏈 https://rinkeby.etherscan.io/
(1) 查看特定位址的相關資訊。
(2) 智能合約上鏈後確認合約。
(3) 從這個位址 https://rinkeby.etherscan.io/address/0x001acd0e33028dd09421bd649a52281f9f3251c3 試著尋找購買NFT (價格 0.3 ETH,盲盒)。

張貼留言

0 留言