如何構建無伺服器智慧合約自動化專案

買賣虛擬貨幣

作者 |Yos Riady

譯者|火火醬,責編 | 李雪敬

頭圖 |CSDN 下載自視覺中國

“智慧合約”這個名字其實並不確切。儘管名字中有“智慧”二字,但 Ethereum 上的智慧合約並不能全自動執行。智慧合約程式碼的執行需要藉助外力的觸發。換句話說,我們需要透過一些外部流程來觸發智慧合約。

在本文中,我們將透過構建可行的解決方案來解決該問題,瞭解一下:

為什麼需要鏈下智慧合約自動化

智慧合約自動化的用例

如何藉助無伺服器架構來部署無伺服器功能

最後,我們還將介紹 serverless-ethers——全功能的智慧合約自動化服務,部署後可直接使用。我們可以以此服務為基礎,構建符合自己需求的自定義智慧合約自動化專案。

問題是:名叫智慧合約,卻無法自動執行

假設我們想要實現一個能夠每小時自動執行一次的智慧合約。要怎麼做呢?

現實就是:根本做不到。僅靠 Solidity 智慧合約是做不到這一點的。儘管名叫“智慧合約”,但 Ethereum 中的智慧合約並不能自動執行,我們需要藉助外部源(人或機器)來呼叫智慧合約並執行其程式碼。

合約最多能做到的是:在不同任務間插入一小時間隔,例如:

functionrunMe()public{require(block.timestamp>=lastTriggeredAt+1hour);...}

以上“require()”語句可確保兩次執行至少間隔一小時。但是,仍需要在開始時人為觸發智慧合約,然後程式碼才會正常執行。

來談一談“自動e執行”

從技術層面上來看,有一些操作是可以使用函式修改器來自動執行的。比如說Compound Governance的COMP分配。一旦地址獲得了0.001COMP,之後所有的Compound交易(例如提供資產,或轉移cToken)都會自動將COMP轉到其錢包中。

我們可以在函式修改器中實現上述邏輯,將修改器放在函式前,並在呼叫函式時自動執行邏輯。由呼叫方來支付相關的附加費用。

然而,並不是所有的智慧合約系統都可以採用這種方法。由於這些修改器只能在特定條件下執行,因此可能會導致意料之外的gas費用。同時,還可能會向使用者隨機收取額外的gas費用,以實現合約“平衡性”。

並且,程式碼的執行仍然需要透過人為呼叫智慧合約才能實現。

智慧合約自動化的常見用例

DeFi協議依賴於某種鏈下智慧合約自動化。MakerDAO依賴第三方來監控債務頭寸的抵押擔保比率,並清算擔保不足的頭寸。其他的DeFi協議也都有類似的需求。

在鏈下智慧合約自動化方面,有兩個常見用例:

自動觸發器(Automated Triggers):在特定情況下執行合約。

狀態和事件監控(State and Event Monitoring):瞭解合約在何時出現特定狀態。

1. 自動觸發器

我們經常需要定期、或在特定條件下執行合約,例如:

週期性地恢復平衡池

結束DAO/治理過程中的投票

按比例支付安全代幣股息

2. 狀態和事件監控

有時我們需要了解合約是否滿足了某些條件,例如:

瞭解智慧合約的價值是否發生了變化

獲取所有準入限制更改的通知

瞭解何時發出特定的智慧合約事件

解決方案:無伺服器函式?

實際上,無伺服器功能剛好適用於上面提到的這幾個用例。有了無伺服器化,我們便無需在部署程式碼之前預配任何東西,並且之後也不需要費心管理,極大地簡化了問題的解決方案。

快速入門:藉助Serverless Framework來實現無伺服器化

無伺服器架構(Serverless Framework)為我們提供了開發、部署、監控和保護無伺服器應用程式所需的一切內容。讓我們一起來看看如何能夠以最簡單的方式完成開發吧。

>npminstall-gserverless>serverless-vx.x.x

首先,我們來快速瞭解一下Serverless Framework的運作方式。

0. serverless.yml

所有Serverless服務中的Lambda函式和事件都可以在名為serverless.yml的配置檔案中找到。該檔案對服務(包含Functions和Events)進行了定義。

service:serverless-ethersprovider:name:awsruntime:nodejs12.xenvironment:CHAIN_ID:3DEFAULT_GAS_PRICE:60000000000functions:myFunc:handler:functions/myFunc.handlerevents:-schedule:rate(2hours)

我們可以在function屬性下,對無伺服器函式進行定義。在上面的例子中:

我們有名為myFunc的Function

handler屬性指向包含你想在函式中執行的程式碼的檔案和模組

events屬性為要執行的函式指定Event觸發器

一個服務中可以包含多個函式。

1. Functions

Function是AWS Lambda函式,是一個類似於微服務的獨立部署單元。作為一段部署在雲中的程式碼,通常被用於執行單個作業。

//functions/myFunc.jsexports.handler=asyncfunction(event,context){//Doanything};

Functions只是普通的JS函式,可以將事件物件作為有效負載。

2. Events

Events是觸發函式執行的事件,隸屬於每個Function,可以在serverless.yml中的事件屬性中找到。

我們可以使用Scheduled Events觸發器來定期自動執行函式。例如,我們指定每2小時執行一次myFunc函式:

#serverless.ymlfunctions:myFunc:handler:functions/myFunc.handlerevents:-schedule:rate(2hours)

我們還可以藉助cron schedule expression來指定安排計劃

#serverless.ymlevents:-schedule:cron(012**?*)#12PMUTC

如果你使用的是AWS的話,事件即為AWS中可以出發AWS Lambda函式的任意事件,比如:

AWS API Gateway HTTP端點請求(例如,REST API)

AWS S3儲存桶上傳(例如,影象)

CloudWatch計時器(例如,每5分鐘執行一次)

AWS SNS主題(例如,資訊)

等等……

就目前而言,知道這些就夠了。如果還想了解更多關於Serverless framework的內容的話,可以看一下這個檔案(https://www.serverless.com/framework/docs/?ref=hackernoon.com)

在瞭解了Serverless Framework的基礎知識後,我們來看一看serverless-ethers服務吧。

serverless-ethers是什麼

serverless-ethers是一個全功能Serverless服務,部署後即可直接使用。

[email protected]:yosriady/serverless-ethers.gitcdserverless-ethersnvmusenpminstall

我們可以將此專案作為構建自定義智慧合約自動化的基礎。其預先配置的是AWS,但修改後也適用於其他雲提供商(如GCP、Azure等)。

serverless-ethers專案的結構如下:

├──contracts/│├──abis/│├──abis.js│└──addresses.js├──functions/│└──exec.js└──serverless.yml

contracts/包含智慧合約ABI和地址。

functions/包含實現業務邏輯的JS函式。

serverless.yml描述服務配置。

接下來,我們將深入瞭解一下各個部分。

合約樣本示例

為了進行測試,我編寫並部署了一個智慧合約示例:

//SPDX-License-Identifier:GPL-3.0pragmasolidity^0.6.10;contractDummyStorage{eventWrite(addressindexedsource,uint256value);uintinternal_currentValue;functionget()publicviewreturns(uint){return_currentValue;}functionput(uintvalue)public{emitWrite(msg.sender,value);_currentValue=value;

該DummyStorage智慧合約具有以下功能:

get是一個能反饋合約當前值的只讀函式。

put是一個用於更新合約當前值的寫入函式。

該示例合約已經過驗證並在Ropsten上執行。大家可以用它來測試自己的函式!

1. 智慧合約ABIs

合約目錄中包含與函式互動的合約ABIs。在示例專案中,它包含DummyStorage合約的ABI。

├──contracts/│├──abis/││└──DummyStorage.json│├──abis.js│└──addresses.js

我們可以將ABI看作是智慧合約的公共API規範,類似於OpenAPI規範。我們需要用ABI來呼叫合約函式。

合約/目錄結構能協助我們匯入合約ABI和地址:

//functions/exec.jsconst{abis,addresses}=require('../contracts');constDummyStorageABI=abis.DummyStorage;constDummyStorageAddress=addresses.DummyStorage

這都是我們在接下來的函式部分中將要用到的。

2. Functions

exec函式利用Ethers來載入合約ABI並呼叫智慧合約:

//Initializecontractconstcontract=newethers.Contract(DummyStorageAddress,DummyStorageABI,wallet,)//Callsmartcontractfunction`put(uint)`constRANDOM_INTEGER=Math.floor(Math.random()*100);//returnsarandomintegerfrom0to99consttx=awaitcontract.put(RANDOM_INTEGER)

載入合約ABI和地址後,我們將得到一個具備智慧合約所有函式的ethers.Contract抽象,包括get()和put().

在示例exec函式中,我們用一個隨機整數來呼叫contract.put()。

3. serverless.yml

在執行exec函式之前,我們需要在serverless.yml中指定幾個環境變數:

#serverless.ymlservice:serverless-ethersprovider:name:awsruntime:nodejs12.xregion:ap-southeast-1timeout:30environment:DEFAULT_GAS_PRICE:60000000000MNEMONIC:...SLACK_HOOK_URL:...

serverless-ethers使用了以下環境變數:

DEFAULT_GAS_PRICE:事務寫入時使用的預設gas價格。

MNEMONIC:用於匯出Ethereum地址的12個助記詞。如果打算將資料寫入Ethereum的話,要確保確保其由Ether進行支付。

SLACK_HOOK_URL:示例中使用Incoming Webhooks向Slack傳送訊息。你可以從自己的Slack儀表板上獲取此URL。(可選項)

你可以從AWS Lambda控制檯更改已部署函式的環境變數。

注意:切記不要在構建過程中用明文儲存金鑰。在儲存助記詞和API金鑰等憑證時,要使用安全的引數儲存,如AWS Secrets Manager。因為每個專案的安全需求和設定不同,所以請根據自身實際情況來決定密碼儲存方式。

本地執行

我們可以使用無伺服器CLI命令在本地執行函式。

>serverlessinvokelocal-fexecStarting...ContractABIsloadedEtherswalletloadedContractloadedSendingtransaction...:white_check_mark:Transactionsenthttps://ropsten.etherscan.io/tx/0x72204f07911a319b4e5f7eb54ad15ed666cfc1403b53def40c9d60188b176383CompletedTrue

部署到AWS

執行serverless deploy即可輕鬆實現部署:

>serverlessdeployServerless:Packagingservice...Serverless:Excludingdevelopmentdependencies...Serverless:CreatingStack...Serverless:CheckingStackcreateprogress...........Serverless:Stackcreatefinished...Serverless:UploadingCloudFormationfiletoS3...Serverless:Uploadingartifacts...Serverless:Uploadingserviceserverless-ethers.zipfiletoS3(2.95MB)...Serverless:Validatingtemplate...Serverless:UpdatingStack...Serverless:CheckingStackupdateprogress........................Serverless:Stackupdatefinished...ServiceInformationservice:serverless-ethersstage:devregion:ap-southeast-1stack:serverless-ethers-devresources:8apikeys:Noneendpoints:Nonefunctions:exec:serverless-ethers-dev-execlayers:None

現在,一個無伺服器函式就完成了,我們可以用它來對智慧合約進行自動化和監控,並且可以在這個示例專案的基礎上構建屬於自己的智慧合約自動化。

寫在最後

祝賀你學會了以下內容:

為什麼需要鏈下智慧合約自動化

智慧合約自動化的用例

Serverless架構

serverless-ethers示例應用程式的執行原理

補充:用Slack 實現ChatOps

除了serverless-ethers,我們還可以透過postToSlack函式來整合Slack。

constsuccessMessage=`:white_check_mark:Transactionsenthttps://ropsten.etherscan.io/tx/${tx.hash}`;awaitpostToSlack(successMessage);

postToSlack函式利用了你從Slack console獲取的SLACK_HOOK_URL環境變數。設定完成後,只要交易成功傳送,就會馬上通知Slack,輕輕鬆鬆監控函式。

補充:監控智慧合約事件

截至目前,我們只介紹了“自動觸發”用例,那要怎樣監控智慧合約狀態和事件呢?

我們可以使用Ethers v5 Events API來定期監控特定事件。可以在函式中執行以下操作:

//GiventhefollowingEvent://eventTransfer(bytes32indexednode,addressowner)//Getthefilter(thesecondnullcouldbeomitted)constfilter=contract.filters.Transfer(userAccount,null);//Querythefilterconstlogs=contract.queryFilter(filter,0,"latest");//fromblock0tolatestblock//Printoutallthevalues:logs.forEach((log)=>{console.log(log.args._to,log.args._value);}

假設我們希望讓這個函式週期性執行(例如每5分鐘一次),還需要儲存一個標記,對該函式自上次執行後所看到的最後一個塊進行跟蹤。

該智慧合約在監控Access Control白名單時非常有用。有了事件監控功能,可以在白名單中新增新地址時通知Slack。你用過嗎?

免責聲明:

  1. 本文版權歸原作者所有,僅代表作者本人觀點,不代表鏈報觀點或立場。
  2. 如發現文章、圖片等侵權行爲,侵權責任將由作者本人承擔。
  3. 鏈報僅提供相關項目信息,不構成任何投資建議

推荐阅读

;