如何构建无服务器智能合约自动化项目
为什么需要链下智能合约自动化 智能合约自动化的用例 如何借助无服务器架构来部署无服务器功能
function runMe() public {
require(block.timestamp >= lastTriggeredAt + 1 hour);
...
}
自动触发器(Automated Triggers):在特定情况下执行合约。 状态和事件监控(State and Event Monitoring):了解合约在何时出现特定状态。
周期性地恢复平衡池 结束DAO/治理过程中的投票 按比例支付安全代币股息
了解智能合约的价值是否发生了变化 获取所有准入限制更改的通知 了解何时发出特定的智能合约事件
> npm install -g serverless
> serverless -v
x.x.x
service: serverless-ethers
provider:
name: aws
runtime: nodejs12.x
environment:
CHAIN_ID: 3
DEFAULT_GAS_PRICE: 60000000000
functions:
myFunc:
handler: functions/myFunc.handler
events:
- schedule: rate(2 hours)
我们有名为myFunc的Function handler属性指向包含你想在函数中运行的代码的文件和模块 events属性为要执行的函数指定Event触发器
// functions/myFunc.js
exports.handler = async function(event, context) {
// Do anything
};
# serverless.yml
functions:
myFunc:
handler: functions/myFunc.handler
events:
- schedule: rate(2 hours)
# serverless.yml
events:
- schedule: cron(0 12 * * ? *) # 12PM UTC
AWS API Gateway HTTP端点请求(例如,REST API) AWS S3存储桶上传(例如,图像) CloudWatch计时器(例如,每5分钟运行一次) AWS SNS主题(例如,信息) 等等……
git clone git@github.com:yosriady/serverless-ethers.git
cd serverless-ethers
nvm use
npm install
├── contracts/
│ ├── abis/
│ ├── abis.js
│ └── addresses.js
├── functions/
│ └── exec.js
└── serverless.yml
contracts/包含智能合约ABI和地址。 functions/包含实现业务逻辑的JS函数。 serverless.yml描述服务配置。
// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.6.10;
contract DummyStorage {
event Write(address indexed source, uint256 value);
uint internal _currentValue;
function get() public view returns (uint) {
return _currentValue;
}
function put(uint value) public {
emit Write(msg.sender, value);
_currentValue = value;
get是一个能反馈合约当前值的只读函数。 put是一个用于更新合约当前值的写入函数。
├── contracts/
│ ├── abis/
│ │ └── DummyStorage.json
│ ├── abis.js
│ └── addresses.js
// functions/exec.js
const { abis, addresses } = require('../contracts');
const DummyStorageABI = abis.DummyStorage;
const DummyStorageAddress = addresses.DummyStorage
// Initialize contract
const contract = new ethers.Contract(
DummyStorageAddress,
DummyStorageABI,
wallet,
)
// Call smart contract function `put(uint)`
const RANDOM_INTEGER = Math.floor(Math.random() * 100); // returns a random integer from 0 to 99
const tx = await contract.put(RANDOM_INTEGER)
# serverless.yml
service: serverless-ethers
provider:
name: aws
runtime: nodejs12.x
region: ap-southeast-1
timeout: 30
environment:
DEFAULT_GAS_PRICE: 60000000000
MNEMONIC: ...
SLACK_HOOK_URL: ...
DEFAULT_GAS_PRICE:事务写入时使用的默认gas价格。 MNEMONIC:用于导出Ethereum地址的12个助记词。如果打算将数据写入Ethereum的话,要确保确保其由Ether进行支付。 SLACK_HOOK_URL:示例中使用Incoming Webhooks向Slack发送消息。你可以从自己的Slack仪表板上获取此URL。(可选项)
> serverless invoke local -f exec
Starting...
Contract ABIs loaded
Ethers wallet loaded
Contract loaded
Sending transaction...
:white_check_mark: Transaction sent https://ropsten.etherscan.io/tx/0x72204f07911a319b4e5f7eb54ad15ed666cfc1403b53def40c9d60188b176383
Completed
True
> serverless deploy
Serverless: Packaging service...
Serverless: Excluding development dependencies...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service serverless-ethers.zip file to S3 (2.95 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
.....................
Serverless: Stack update finished...
Service Information
service: serverless-ethers
stage: dev
region: ap-southeast-1
stack: serverless-ethers-dev
resources: 8
api keys:
None
endpoints:
None
functions:
exec: serverless-ethers-dev-exec
layers:
None
为什么需要链下智能合约自动化 智能合约自动化的用例 Serverless架构 serverless-ethers示例应用程序的运行原理
const successMessage = `:white_check_mark: Transaction sent https://ropsten.etherscan.io/tx/${tx.hash}`;
await postToSlack(successMessage);
// Given the following Event:
// event Transfer(bytes32 indexed node, address owner)
// Get the filter (the second null could be omitted)
const filter = contract.filters.Transfer(userAccount, null);
// Query the filter
const logs = contract.queryFilter(filter, 0, "latest"); // from block 0 to latest block
// Print out all the values:
logs.forEach((log) => {
console.log(log.args._to, log.args._value);
}