本文將不多介紹Truffle是什麼工具,先假設各位已經知道其用途。本文也不會詳細介紹Truffle所有指令,純粹介紹對於智能合約開發者在測試時基本會有的流程。
若真的還不太知道Truffle的用途,可至官方Docs學習!
也請在Docs跟著說明先進行Truffle的安裝。
本文將使用open-zeppelin的ERC20範例合約進行示範,智能合約程式碼:
記得將此智能合約相關之所有智能合約都放在後面會提到的contracts/資料夾內!
另外測試網路(鏈)是直接使用Ganache啟動單機網路(鏈),較為簡單方便。
故後面會提到的truffle-config.js當中,記得將networks設定為:
development: {
host: "127.0.0.1",
port: 7545,
network_id: "*"
}
(1) 初始化 — truffle init
$ truffle initStarting init...
================
> Copying project files to /yourWorkspaceDir
Init successful, sweet!
這個步驟會自動幫你產生truffle所需的基本檔案架構,包含contracts/、migrations/、truffle-config.js。其中contracts/Migrations.sol與migrations/1_initial_migration.js在後續測試當中都需要保留。
(2) 編譯合約 — truffle compile
$ truffle compileCompiling your contracts...
===========================
> Compiling ./contracts/GSN/Context.sol
> Compiling ./contracts/Migrations.sol
> Compiling ./contracts/math/SafeMath.sol
> Compiling ./contracts/token/ERC20/ERC20.sol
> Compiling ./contracts/token/ERC20/IERC20.sol
> Artifacts written to /yourWorkspaceDir/build/contracts
> Compiled successfully using:
- solc: 0.6.1+commit.e6f7d5a4.Emscripten.clang
這個步驟會去編譯合約(若程式碼有錯誤就不會成功,錯誤訊息會顯示在console中),並將該合約的相關資訊(像是abi、bytecode之類的)透過json格式存於build/contracts當中。
在此有遇到一個小地方需要注意,第一次執行時,出現這樣的錯誤:
Error: Truffle is currently using solc 0.5.16, but one or more of your contracts specify "pragma solidity >=0.6.0 <0.8.0".Please update your truffle config or pragma statement(s).(See https://trufflesuite.com/docs/truffle/reference/configuration#compiler-configuration for information onconfiguring Truffle to use a specific solc compiler version.)
原因在於一開始init時,產生truffle-config.js設定檔當中,compilers.solc的所有設定都是註解掉的(使用預設的意思)。所以在將compilers.solc.version設定為”0.6.1"之後即可正常執行build了!(這裡設定0.6.1是因為open-zeppelin的ERC20相關合約都是使用 pragma solidity >=0.6.0 <0.8.0;,所以truffle預設的0.5.16並不符合智能合約程式碼的版本。
(3) deploy合約 — truffle migrate
首先是將合約deploy到測試鏈當中,這裡需要對migrations/中的檔案進行編輯。基本要deploy合約的話會需要這兩個檔案:
.
├── 1_initial_migration.js
└── 2_deploy_contracts.js //一開始沒有這個檔案,要自己增加
1_initial_migration.js這個檔案跟contracts/Migrations.sol一樣,都不要刪掉它,是用來管理智能合約用的。
主要是要透過2_deploy_contracts.js來進行合約的deploy,以下是基本寫法:
const ERC20 = artifacts.require("ERC20");module.exports = function(deployer) {
deployer.deploy(ERC20, "test2", "TST2");
};
接著就可以透過truffle migrate進行合約deploy(此步驟一樣會執行編譯),記得先確認truffle-config.js當中是否已設定好networks:
$ truffle migrateCompiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Starting migrations...
======================
> Network name: 'development'
> Network id: 5777
> Block gas limit: 6721975 (0x6691b7)1_initial_migration.js
======================
Replacing 'Migrations'
----------------------> transaction hash: 0xfd62a74ad818a31c00e7dad9354c9706430e546902f6199d0a82d891c1538d48> Blocks: 0 Seconds: 0
> contract address: 0x9cE0e40E5392A5996672377B9c3E65f605e95A36
> block number: 9
> block timestamp: 1609814807
> account: 0x4faB2E6E916859F5fb06d445008cA0A8EeD402A2
> balance: 99.94315274
> gas used: 192159 (0x2ee9f)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.00384318 ETH
> Saving migration to chain.
> Saving artifacts-------------------------------------
> Total cost: 0.00384318 ETH2_deploy_contracts.js
=====================
Replacing 'ERC20'
-----------------
> transaction hash: 0xddb085bc4dd2220588a42f5fb47d4cd32eec9231b4c8556b5c2d2295cd10dee5> Blocks: 0 Seconds: 0
> contract address: 0xBb70762e5B5ADE326Dbb8F86f93b72BF0C41399b
> block number: 11
> block timestamp: 1609814807
> account: 0x4faB2E6E916859F5fb06d445008cA0A8EeD402A2
> balance: 99.92104016
> gas used: 1063291 (0x10397b)
> gas price: 20 gwei
> value sent: 0 ETH
> total cost: 0.02126582 ETH
> Saving migration to chain.
> Saving artifacts
-------------------------------------
> Total cost: 0.02126582 ETHSummary
=======
> Total deployments: 2
> Final cost: 0.025109 ETH
deploy成功的話,會顯示該筆交易的詳細內容,也包含合約地址。
但當你想再次deploy的時候,若智能合約程式碼沒有變動,會顯示:
$ truffle migrateCompiling your contracts...
===========================
> Everything is up to date, there is nothing to compile.
Network up to date.
此時就要將指令加上 — reset即可
$ truffle migrate --reset
(4) 操作智能合約 — truffle console
首先輸入指令進入console
$ truffle console
truffle(development)>
接著可以用兩種方法來跟合約互動:
(a) 對最近一個deploy的合約互動
truffle(development)> let instance = await ERC20.deployed()
undefinedtruffle(development)> instance.name()
'test2'
(b) 對之前deploy過的某個合約互動(要知道合約地址)
truffle(development)> let instance = await ERC20.at("0xBb70762e5B5ADE326Dbb8F86f93b72BF0C41399b")
undefinedtruffle(development)> instance.symbol()
'TST2'
如此一來就可以透過指令的方式來呼叫智能合約上的function,進行簡易的測試。
(5) 測試智能合約 — truffle test
透過truffle console的方式也能夠測試智能合約沒錯,但不可能每一次都要慢慢的一行一行打指令進行測試。所以truffle也可以使用類似自動化script的方式進行測試(類似在寫js的unit test)。
將測試script放在test/當中,而官方表示可以使用兩種語言進行測試,分別是JS以及Solidity。
以下使用JS進行測試:
首先在test/中建立檔案ERC20.test.js
const ERC20 = artifacts.require('ERC20');contract('ERC20', function () {
const tokenName = 'test2';
const tokenSymbol = 'TST2'; it(`should return Name:${tokenName}, Symbol:${tokenSymbol}`, async () => {
let instance = await ERC20.deployed();
let name = await instance.name.call();
let symbol = await instance.symbol.call(); assert.equal(name, tokenName, "Name不正確");
assert.equal(symbol, tokenSymbol, "Symbol不正確");
});});
tokenName與tokenSymbol分別設定為’test2'、’TST2'是跟前面2_deploy_contracts.js中設定的一樣。程式碼當中的合約互動方式基本上與truffle console操作相同,主要在assert的判斷部分。
這裡只是很單純的用呼叫name、symbol來當成範例,實際可以測試的東西還非常多,例如:transfer、approve之類ERC20合約常用功能。也可以參考open-zeppelin的測試程式。
執行測試:
$ truffle testUsing network 'development'.
Compiling your contracts...===========================
> Everything is up to date, there is nothing to compile.Contract: ERC20
✓ should return Name:test2, Symbol:TST2 (56ms)1 passing (153ms)
以上便是一個很基本的truffle使用範例,適合剛接觸Ethereum Smart Contract的開發者,希望對各位有幫助!
最終資料夾檔案架構:
$ tree .
.
├── build
│ └── contracts
│ ├── Context.json
│ ├── ERC20.json
│ ├── IERC20.json
│ ├── Migrations.json
│ └── SafeMath.json
├── contracts
│ ├── GSN
│ │ └── Context.sol
│ ├── Migrations.sol
│ ├── math
│ │ └── SafeMath.sol
│ ├── token
│ │ └── ERC20
│ │ ├── ERC20.sol
│ │ └── IERC20.sol
├── migrations
│ ├── 1_initial_migration.js
│ └── 2_deploy_contracts.js
├── test
│ └── ERC20.test.js
└── truffle-config.js
參考資料: