編寫樂透智能合約
本次將篇寫一個智能合約的樂透程式,開發環境使用Remix。
構想如下:
這個智能合約會包含資金池跟玩家的錢包地址。
這個智能合約需要所有玩家投入一定的資金(例如最少一個以太幣),才能參加遊戲。另外該智能合約需要知道最後誰是贏家,而這需要莊家還告知。
一旦被告知贏家(哪個錢包地址)是誰,合約會自動將資金發送給該玩家。這在這個遊戲中我們就會有以下的變量(variables)跟函數(function),如下表。
這個合約中我們會用到不同的資料型態,關於智能合約的資料型態請參照以太坊智能合約編寫part1。而在智能合約中有所謂的全局變量,它有如下表的四種型態:
我們會用到msg.sender跟msg.value。哪甚麼是msg呢?msg就是指如下圖的組合。
或是
接下來我們需要一個亂數功能來產生贏家,在Solidity,我們並不用亂數產生器。我們使用以下方式來產生。
根據上面的需求,第一版的智能合約大概如下
我們有了亂數產生器之後,要使用這個亂數產生贏家。我們採用亂數除上玩家人數的餘數數學操作。例如10 / 3 餘數為1。
這裡要說明的是玩家人數的資料(array)中呈現的是index的方式。例如array中有
[jason, bob, Alice] — 哪index就會是0–2。
我們還少了一行,就是合約會在得知贏家是誰後自動將合約中所有的以太幣給贏家。
到了這裡我們只能讓這個智能合約玩一回合,理論上這個遊戲應該可以一直循換下去,所以我們的流程應該是要如下的流程。
所以在選擇贏家的函數中應該要再加上一行。
“[]”標示我們使用動態的array(因為我們沒有限定玩家人數),另外(0)是告訴合約我們要一個新的array裡面的初始數字為零。
這個選擇贏家的函數到這裡有一個安全的隱憂。哪就是這個函數設定是public的,意味著任何人都可以呼叫這個函數產生贏家。這會讓遊戲可能具有操縱性,因為我們的亂數產生參數中使用到now(也就使呼叫這個函數的地址的time stamp),所以我們需要指定只有莊家才可以呼叫此函數。
減少重複代碼的功能: modfier
solidity有一個功能可以減少讓我們重複寫code的功能,這個稱為modfier。我們智能合約的pickWinner函數限制只能由莊家的錢包地址來執行。如果是取亂數的函數也需要只能由莊家執行呢?哪這樣等於要在random函數中加上
require(msg.sender == bookmaker)
這等於重複了代碼。所以我們可以借用modfier功能。
在上面的新增的代碼中,我們增加了一個名為bookmaker_only的modifier函數。一樣有一樣的require的代碼,但是往下家有一行只有一個底線的標示。這個意思是當其他的函數,例如pickWinner執行到bookmaker_only這個函數時,其實就會把bookmaker_only接下去的函數一起執行(如下圖)。
最後我們要加上玩家清單的函數
整個智能合約的完整內容就會像下圖一樣
驗證
合約佈署完成後,我們用Remix提供的account來當作莊家與玩家(如下圖)。
第一個account當作玩家,所以佈署此合約跟亂數與開獎的函數一定只有這個account。玩家只能使用enter函數參加遊戲。
上圖中我們可以看到玩家有三個錢幫地址(0x開頭),跟合約中有3個以太幣。然後我們要用莊家的帳號來開獎並自動轉帳。
上圖中我們可以看到,當開獎之後。某一個錢包的以太幣比之前增加了2個(扣掉自己投注的一個)。合約中中的以太幣跟玩家清單都歸零了。準備下一輪的遊戲。