本体技术视点 | 关于本体EVM合约开发,你必须知道的事(二)

本体Ontology
企业专栏
热度: 12256
本期为您介绍开发环境工具以及使用MetaMask管理密钥

合约

上周,本体宣布支持 EVM 的测试网正式部署并向全球开发者开放 EVM 兼容公测。同时,与知名代码审计机构慢雾科技合作发布《本体安全漏洞与威胁情报赏金计划》(https://slowmist.io/en/ontology/)正式启动,上报单个有效漏洞奖励最高可达12,000美金。

合约为方便广大社区开发者们能够快速便捷地熟悉本体 EVM 开发环境,我们特地为您准备了“关于本体 EVM 合约开发,你必须知道的事!”,助力您的开发。

上一期,我们介绍了和本体 EVM 相关的 ChainID、RPC URL、浏览器地址等配置信息,开发者可以根据上述信息,配置 MetaMask 数据客户端到本体网络。这一期,我们将介绍在本体上开发和部署 EVM 合约的工具,以及如何使用 MetaMask 插件数据客户端来管理以太坊数据客户端。

第二部分 开发环境工具简介

鉴于 EVM 合约使用 Solidity(https://solidity-cn.readthedocs.io/zh/develop/index.html) 语言开发,我们将介绍如何搭建 Remix、Truffle 和 Hardhat 开发环境,进合约开发、编译、部署、调试等一系列工作。此外,开发者也可直接复用现有的以太坊合约框架在 Ontology 上开发和部署 EVM 合约。

2.1 Remix 开发环境

Remix IDE 是一个开源的 Solidity 合约集成开发环境,支持用户进行合约开发、编译、部署、调试等工作。Remix IDE 的官方英文版文档请见此链接(https://remix-ide.readthedocs.io/en/latest/)。

下面我们通过一个 Hello World 合约样例来展示如何使用 Remix。

2.1.1 安装开发环境

首次使用 Remix 需要在 PLUGIN MANAGER 里面找到并添加 Solidity Compiler 和 Deploy and Run Transactions 模块到编译器中。

合约

然后选择 Solidity 环境,创建新文件并命名为 HelloWorld.sol,再将已经写好的 Hello World 合约代码(https://github.com/ontio/ontology/blob/master/docs/specifications/evm_refernce/contract-demo/helloworlddemo/helloworld.sol)复制到该文件中。

合约

2.1.2 编译合约

点击 Solidity Compiler 按钮,选择编译器版本为 0.5.10,开始编译 HelloWorld.sol。

2.1.3 部署合约

编译后可以将合约部署到本体网络中。下面将以测试网作为范例。在部署合约之前,需要将 MetaMask 数据客户端连接到本体网络(可参考上期技术视点),并在本体Faucet地址(https://developer.ont.io/)上领取测试 ONG 作为手续费。

然后,在 Remix 环境中选择“Injected Web3”,最后点击“Deploy”完成合约部署。

合约

2.1.4 调用合约

合约部署后,开发者可以调用合约中的方法。部署示例中的 Hello World 合约时, Hello 字符串会存入合约,我们可以调用合约的 message 方法来查询这个字符串,如下图:


合约2.2 Truffle 开发环境

Truffle 是一个用于辅助以太坊智能合约开发、测试和管理的框架,官方文档请参考此链接(https://truffle.tryblockchain.org/Truffle-introduce-介绍.html)。

下面我们用这段测试代码(https://github.com/ontio/ontology/tree/master/docs/specifications/evm_refernce/contract-demo/truffledemo)作为范例介绍 Truffle 的使用。

2.2.1 安装开发环境

初始化开发环境,首先安装 Truffle 环境需要的配置文件。

  • Node.js v8+ LTS and npm (https://nodejs.org/en/)(comes with Node)
  • Git(https://git-scm.com/)

然后通过以下命令安装 Truffle。

$ npm install -g truffle

2.2.2 配置 truffle-config

  • 首先创建 .secret 来存储测试助记词或者私钥(可在 MetaMask 里面找到)
  • 然后按照以下内容修改 truffle-config 文件

const HDWalletProvider = require('@truffle/hdwallet-provider');

const fs = require('fs');

const mnemonic = fs.readFileSync(".secret").toString().trim();

module.exports = {

 networks: {

  ontology: {

  provider: () => new HDWalletProvider(mnemonic, `http://polaris2.ont.io:20339`),

  network_id: 5851,

  port: 20339,      // Standard Ethereum port (default: none)

  timeoutBlocks: 200,

  gas:800000,

  skipDryRun: true

  }

 },

 compilers: {

  solc: {

   version: "0.5.16",  // Fetch exact version from solc-bin (default: truffle's version)

   docker: false,    // Use "0.5.1" you've installed locally with docker (default: false)

   settings: {     // See the solidity docs for advice about optimization and evmVersion

   optimizer: {

    enabled: true,

    runs: 200

   },

   evmVersion: "byzantium"

   }

  }

 }

};

2.2.3 部署合约到本体网络

执行如下的命令部署合约。


$ truffle migrate --network ontology

显示如下输出则代表部署成功。

注意: 编写测试脚本时尽量不要使用以太坊通证的单位(如 wei、gwei、ether 等)。

Compiling your contracts...

===========================

> Everything is up to date, there is nothing to compile.


Starting migrations...

======================

> Network name:  'ontology'

> Network id:   5851

> Block gas limit: 0 (0x0)

1_initial_migration.js

======================


 Replacing 'Migrations'

 ----------------------

 > transaction hash:  0x9019551f3d60611e1bc6b323f3cf3020d15c8aeb06833d14ff864e24622884aa

 > Blocks: 0      Seconds: 4

 > contract address:  0x53e137A51CfD1E1b088E0d921eB5dBCF9cFa955E

 > block number:    6264

 > block timestamp:  1624876467

 > account:      0x4e7946D1Ee8f8703E24C6F3fBf032AD4459c4648

 > balance:      0.00001

 > gas used:      172969 (0x2a3a9)

 > gas price:     0 gwei

 > value sent:     0 ETH

 > total cost:     0 ETH



 > Saving migration to chain.

 > Saving artifacts

 -------------------------------------

 > Total cost:         0 ETH



2_deploy_migration.js

=====================


 Replacing 'HelloWorld'

 ----------------------

 > transaction hash:  0xf8289b96f2496a8c940ca38d736a554a90f64d927b689921781619499906721b

 > Blocks: 0      Seconds: 4

 > contract address:  0xfbff9bd546B0e0D4b40f6f758847b70050d01b37

 > block number:    6266

 > block timestamp:  1624876479

 > account:      0x4e7946D1Ee8f8703E24C6F3fBf032AD4459c4648

 > balance:      0.00001

 > gas used:      243703 (0x3b7f7)

 > gas price:     0 gwei

 > value sent:     0 ETH

 > total cost:     0 ETH


hello contract address: 0xfbff9bd546B0e0D4b40f6f758847b70050d01b37


 > Saving migration to chain.

 > Saving artifacts

 -------------------------------------

 > Total cost:         0 ETH



Summary

=======

> Total deployments: 2

> Final cost:     0 ETH

2.3 Hardhat 开发环境

Hardhat 是一个编译、部署、测试和调试以太坊应用的开发环境。下面我们用这段测试代码(https://github.com/ontio/ontology/tree/master/docs/specifications/evm_refernce/contract-demo/hardhatdemo)作为范例介绍 Hardhat 的使用。

2.3.1 安装开发环境

请参考此安装教程(https://hardhat.org/getting-started/)进行安装。

2.3.2 配置 hardhat-config

  • 按照如下代码修改 hardhat.config.js 文件

require("@nomiclabs/hardhat-waffle");


module.exports = {

  defaultNetwork: "ontology_testnet",

  networks: {

    hardhat: {},

    ontology_testnet: {

      url: "http://polaris2.ont.io:20339",

      chainId: 5851,

      gasPrice:500,

      gas:2000000,

      timeout:10000000,

      accounts: ["你的私钥字符串"]

    }

  },

  solidity: {

    version: "0.8.0",

    settings: {

      optimizer: {

        enabled: true,

        runs: 200

      }

    }

  },

};

2.3.3 部署合约

在项目根目录下执行下面的命令,部署合约到本体测试网。

$ npx hardhat run scripts/sample-script.js --network ontology_testnet

执行结果

$ npx hardhat run scripts/sample-script.js --network ontology_testnet

Contract deployed to: 0xB105388ac7F019557132eD6eA90fB4BAaFde6E81

第三部分 使用 MetaMask 管理密钥

本体网络支持开发者使用 MetaMask 插件来管理以太坊数据客户端私钥。

MetaMask 是一个非托管的数据客户端,用户的私钥通过助记词加密并储存在本地浏览器,一旦用户丢失私钥将无法恢复对其的使用。MetaMask 通过 Infura 接入以太坊,更多详细信息可复制链接浏览(https://metamask.io/)。

3.1 安装 Web3环境

第一步,在 dApp 内安装 web3环境:

$ npm install --save web3

创建一个新的文件,命名为 web3.js ,将以下代码复制到该文件:

import Web3 from 'web3';


const getWeb3 = () => new Promise((resolve) => {

 window.addEventListener('load', () => {

   let currentWeb3;


   if (window.ethereum) {

     currentWeb3 = new Web3(window.ethereum);

     try {

       // Request account access if needed

       window.ethereum.enable();

       // Accounts now exposed

       resolve(currentWeb3);

     } catch (error) {

       // User denied account access...

       alert('Please allow access for the app to work');

     }

   } else if (window.web3) {

     window.web3 = new Web3(web3.currentProvider);

     // Accounts always exposed

     resolve(currentWeb3);

   } else {

     console.log('Non-Ethereum browser detected. You should consider trying MetaMask!');

   }

 });

});


export default getWeb3;

简言之,只要在 Chrome 浏览器上安装了 MetaMask 插件,就可以使用该插件注入的 ethereum 全局变量。

第二步,在你的 client 里引入如下代码:

import getWeb3 from '/path/to/web3';

调用如下函数:

getWeb3()

.then((result) => {

  this.web3 = result;// we instantiate our contract next

});

3.2 设置账户

我们需要从以上创建的 web3实例中获取一个账户来发送交易。

  this.web3.eth.getAccounts()

.then((accounts) => {

  this.account = accounts[0];

})

getAccounts() 函数返回用户在 MetaMask 中的所有账户。accounts[0]是用户当前选择的账户。

3.3 合约初始化

完成以上步骤后,对你的合约进行初始化。

3.4 调用函数

现在你可以使用你刚才创建的合约实例调用任何你想调用的函数。需要特别说明的是:函数 call() 用来完成合约的预执行操作,例如:

  this.myContractInstance.methods.myMethod(myParams)

  .call()

  .then(

    // do stuff with returned values

  )

函数send() 用来调用合约来改变合约状态,例如:

this.myContractInstance.methods.myMethod(myParams)

.send({

from: this.account,gasPrice: 0

}).then (

(receipt) => {

 // returns a transaction receipt}

);

下期,我们将为您带来本体 EVM 合约开发流程演示,敬请期待!


如有任何问题,可通过 research@ont.io 联络我们。

添加本体小姐姐微信(ontology_2020)并备注【技术】可进行技术探讨或加入社群。

合约

声明:本文为入驻“火星号”作者作品,不代表火星财经官方立场。
转载请联系网页底部:内容合作栏目,邮件进行授权。授权后转载时请注明出处、作者和本文链接。 未经许可擅自转载本站文章,将追究相关法律责任,侵权必究。
提示:投资有风险,入市须谨慎,本资讯不作为投资理财建议。
免责声明:作为区块链信息平台,本站所提供的资讯信息不代表任何投资暗示,本站所发布文章仅代表个人观点,与火星财经官方立场无关。虚拟货币不具有法定货币等同的法律地位,参与虚拟货币投资交易存在法律风险。火星财经反对各类代币炒作,请投资者理性看待市场风险。
语音技术由科大讯飞提供