搜索

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

2021-09-15 03:11:02
380 0 0


上周,本体宣布支持 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)并备注【技术】可进行技术探讨或加入社群。


热门回帖