区块链研究实验室 | 如何使用Web3.js构建Dapp

今天将向大家介绍使用web3.js构建去中心化应用程序(Dapp),首先我先向大家介绍我先选择使用web3.js的原因。




在web3.js出现之前,我们与智能合约进行交互的唯一方法是通过以太坊节点提供的json-rpc API去充当json-rpc服务器。那绝非是一件易事!


分散式应用程序具有三个主要组件:
前端:从用户那里获取输入并构建要发送到智能合约的请求。
钱包:签署交易并将其发送到网络。
智能合约:编写dapp的业务逻辑。
感谢web3.js的出现,让您可以知道JSON-RPC调用的底层细节,因为它提供了以太坊json-rpc接口的抽象。因此,您可以使用JavaScript与以太坊节点进行交互。


web3.js的工作方式

综上所述,想要和以太坊进行网络交互,需要将json-rpc调用发送到以太坊节点,这就是web3.js在后台执行的操作。


为了将JavaScript代码转换为json-rpc请求,web3.js使用了 provider 的提供程序,该程序是符合EIP 1193规范的 JavaScript 对象,而且它实现了request负责进行以太坊RPC方法调用的方法。


Web3.js提到自己的实施规范,并使其可用web3.providers,其中,您可以访问以下三个供应商文档:HttpProvider,WebsocketProvider,和IpcProvider。


其他项目也实现了此规范,例如 MetaMask,该提供商将提供者对象注入浏览器中的window.ethereum。较旧的Metamask用于注入web3实例 window.web3。


一旦有了提供者,就可以使用new关键字获取web3的实例:
let web3 = new Web3(Web3.givenProvider || 'ws://some.local-or-remote.node:8546');


在这里您要记住,web3.js需要一个提供程序对象,该对象配置用于签署交易并将其发送到网络的钱包信息。如果您在前端使用web3,则此提供程序将注入到浏览器中,或者使用 websocketprovider 或将要构建自己的对象 IpcProvider。


注意:MetaMask 使用 Infura 作为节点提供程序。所以你的电脑无须安装以太坊客户端就可以与以太坊网络进行交互。


快速浏览API



web3.js不仅允许与以太坊节点通信,而且还允许与Whisper和Swarm节点通信。它带有五个主要软件包:
web3.eth:允许与以太坊区块链和以太坊智能合约进行交互。
web3.bzz:允许与分散文件存储Swarm进行交互。
web3.shh:允许与Whisper协议进行交互以进行广播。
web3.utils:为以太坊dapp提供实用程序功能,例如将字符串转换为十六进制文字,将以太值转换为Wei。
web3.*.net:允许与以太坊节点的网络属性(例如网络ID或对等体计数)进行交互。


使用web3.js构建您的Dapp



现在我们已经掌握了理论,那么让我们开始动手制作第一个dapp。
在此示例中,我们将构建一个问候dapp,该dapp存储一个默认的问候字符串并允许用户对其进行更新。对于钱包,我们将使用 MetaMask。您可以通过单击网站主页上的下载链接来添加扩展名。

1.构建合同并将其部署到网络

首先在工作区中创建一个名为的空项目,greeting 然后使用对其进行初始化 truffle init:
> mkdir greeting> cd greeting> truffle init


假设您已经安装了Truffle。如果还没有,则可以使用以下命令获取它:


npminstall-gtruffle


使用您的编辑器打开项目(我使用的是VS Code)。接下来,编辑truffle-config.js 文件并使用以太坊网络的IP和端口更新网络(您可以使用Ganache)。您还需要配置编译器版本以使用已安装的版本。

如果您还没有Solidity编译器,则可以使用以下命令进行安装:

> npm install -g solc// check the installed version> solc --version


现在,是时候greeting在项目目录中创建合同了。输入以下命令:
> truffle create contract Greeting

复制并粘贴以下代码:

// SPDX-License-Identifier: MITpragma solidity >=0.4.22 <0.8.0;
contract Greeting { string public greeting = "hello";
function sayHello() external view returns (string memory) { return greeting; }
function updateGreeting(string calldata _greeting) external { greeting = _greeting; }}

我们只需要2_deploy_greeting.js在migrations文件夹下添加一个迁移文件:

const Greeting = artifacts.require("Greeting");module.exports = function (deployer) { deployer.deploy(Greeting);};


您现在可以使用以下方法编译智能合约并将其部署到网络上:

> truffle compile> truffle migrate


2.将前端与智能合约连接

设置前端


创建一个名为项目中的新文件夹中 client 有package.json和 index.html 文件:

> mkdir client> cd client> npm init -y> touch index.html

安装web3.js和lite-server依赖项:

> npm i web3 --save> npm i lite-server --save-dev //for running a development server


创建一个名为的新文件夹,src并添加两个脚本:index.js和utils.js。


您还需要使用script标记和web3脚本在HTML文件中添加两个脚本

<script type="text/javascript" src="node_modules/web3/dist/web3.min.js"></script><script type="text/javascript" src="src/utils.js"></script><script type="text/javascript" src="src/index.js"></script>

获取一个web3实例

一旦将web3.js作为项目中的依赖项,您所需要做的就是使用提供者的实例实例化web3对象,以便享受web3所提供的一切。

我们将使用window.ethereum注入到浏览器中的MetaMask提供程序,并按照MetaMask文档window.ethereum.request中的说明,请求用户使用来访问其帐户。

打开utils.js文件并添加以下功能:

const getWeb3 = () => { return new Promise((resolve, reject) => { window.addEventListener("load", async () => { if (window.ethereum) { const web3 = new Web3(window.ethereum); try { // ask user permission to access his accounts await window.ethereum.request({ method: "eth_requestAccounts" }); resolve(web3); } catch (error) { reject(error); } } else { reject("Must install MetaMask"); } }); });};
创建合同实例
要创建合同实例,我们需要合同ABI及其地址。如果您查看构建目录中的工件,则会发现一个名为的文件Greeting.json。打开它,您会找到许多有关合同的信息,包括合同名称,ABI等。


如果滚动到文件的末尾,则会发现一个网络字段,其中包含网络ID。合同已部署,我们将使用它通过web3实例化合同实例的相应地址。


contracts在该client文件夹下创建一个名为的新文件夹,然后将其复制粘贴Greeting.json。您还需要安装jQuery才能读取JSON文件的内容:

> npm i jquery


首先,我们需要使用来获取与MetaMask连接的网络的ID web3.eth.net.getId()。

注意:假设您已经配置了MetaMask以使用Ganache。如果不确定如何操作,可以按照本指南进行操作。

接下来,我们将使用返回的ID从Greeting.json文件中获取合同的地址,该文件还将为我们提供合同ABI并使用以下命令创建合同的实例web3.eth.Contract:

3.与智能合约互动

创建合同实例后,就可以开始使用调用文档的方法myContract.methods.myMethod([arguments]),如docs中所述。

如果要调用的函数是纯函数或只读函数,则需要使用:

myContract.methods.myMethod([arguments]).call()

如果要调用的函数要修改状态(又称事务),则需要使用:

myContract.methods.myMethod([arguments]).send()


完整的代码
const displayGreeting = async (greeting, contract) => { greeting = await contract.methods.sayHello().call(); $("h2").html(greeting);};
const updateGreeting = (greeting, contract, accounts) => { let input; $("#input").on("change", (e) => { input = e.target.value; }); $("#form").on("submit", async (e) => { e.preventDefault(); await contract.methods .updateGreeting(input) .send({ from: accounts[0], gas: 40000 }); displayGreeting(greeting, contract); });};
async function greetingApp() { const web3 = await getWeb3(); const accounts = await web3.eth.getAccounts(); const contract = await getContract(web3); let greeting;
displayGreeting(greeting, contract); updateGreeting(greeting, contract, accounts);}
greetingApp();

作者:链三丰,来源:区块链研究实验室

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

郑重声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,多谢。

留言与评论(共有 0 条评论)
   
验证码:
微信号已复制,请打开微信添加咨询详情!