Dapp初探之Web3.js入门

  •  前言

1. 阅读本文需要了解区块链基本原理及术语,掌握solidity的基本用法。

2. 文本会介绍合约如何应用在前端及web3.js的常用api

  •  引言

你肯定很好奇什么是web3.js?第一反应听起来就是个js库(好吧,确实是这样...),我的任务就是告诉你为什么Dapp需要用到这个库,以及这个库是怎么和合约联合工作的。

以太坊网络是由节点组成,每一个节点都包含了一份区块链的拷贝。当你想要调用一份智能合约的某个方法时,你需要去从其中一个节点中查找并告诉这个节点:

1.想要调用的这个智能合约的地址

2.你想要调用的方法以及传入的参数

以太坊节点只能识别一种叫做JSON-RPC的语言,不要紧张,我们不需要了解这门语言怎么写。web3.js是以太坊提供的一个js库,它封装了以太坊的JSON RPC API,提供了一系列和区块链交互的js对象与函数,包括了查看网络状态、查看本地账户、查看交易、发送交易、编译、部署智能合约等。

下面我们开始正文部分。建议配合:https://cryptozombies.io/zh/lesson/6/chapter/1 食用更加。(本文实际也是在读了这篇教程后的一个总结)

  •  正文

     1. Web3 Provider

              在web3.js里设置web3的provider,告诉代码该和哪个节点交互来处理我们的读写。你可以运行自己的以太坊节点来做privider,但显然,可以更简单一点

               1.1 Infura

                     一个服务,它维护了很多以太节点并提供了一个缓存层实现告诉读取。用infura作为节点提供者,你可以不用自己运营节点就能向以太坊发送、接受信息。引用方法如下:

var web3 = new Web3(new Web3.providers.WebsocketProvider("wss://mainnet.infura.io/ws"));

               1.2  Metamask 

                      一个chrome和firefox的插件。metamask默认使用infura的服务器作为web3提供者,在此基础上,能让用户安全的维护他们的以太坊账户和私钥。

                     使用:该插件把它的web3提供者注入到浏览器的全局js对象web3中,所以可以通过检查web3是否存在,存在就使用当前provider作为提供者。

                     示例代码:

window.addEventListener('load', function() {

  // 检查web3是否已经注入到(Mist/MetaMask)
  if (typeof web3 !== 'undefined') {
    // 使用 Mist/MetaMask 的提供者
    web3js = new Web3(web3.currentProvider);
  } else {
    // 处理用户没安装的情况, 比如显示一个消息
    // 告诉他们要安装 MetaMask 来使用我们的应用
  }

  // 现在你可以启动你的应用并自由访问 Web3.js:
  startApp()

})

              1.3  获取metamask用户中的账户

                     metamask允许用户在扩展中管理多个账户,用户可以随时切换账户,一旦切换账户,就需要相应更新界面。示例:

//通过这句可以获取当前web3的账户
var userAccount = web3.eth.accounts[0]

//如果切换账户,可以用setInterval去刷新
var accountInterval = setInterval(function() {
  // 检查账户是否切换
  if (web3.eth.accounts[0] !== userAccount) {
    userAccount = web3.eth.accounts[0];
    // 调用一些方法来更新界面
    updateInterface();
  }
}, 100);

//显然教程里给的这个方法会消耗一个计时器资源,其实可以监听切换账号的事件,如果事件发生,就刷新一次页面。

 

       2.调用合约

               web3.js需要两个参数调用智能合约:address、ABI

               2.1 两个参数

                     address:即你部署智能合约在以太坊后,获得的一个在以太坊上的永久地址。(合约部署不在本文介绍范围)

                     ABI:一个二进制接口。   以json格式表示合约的方法。当你在以太坊部署合约时,编译器也会给你ABI 

               2.2 连接合约

// 实例化目标合约
//将myABI,myContractAddress替换成你想要连接的合约abi和地址即可
var myContract = new web3js.eth.Contract(myABI, myContractAddress);

               2.3 合约函数调用 

                     2.3.1  call()

                       call用来调用view和pure。只运行在本地节点,不耗gas。调用示例:

//myContract是前面定义的目标合约
//yourWantMethod 是你想要调用的方法的名称,123为传入该方法的参数
myContract.methods.yourWantMethod(123).call()

                    2.3.2  send()

                      send将创建一个事务并改变区块链上的数据,会消耗gas,并会要求弹出对话框请求用户使用metamask对事务签名。所以当调用的函数非pure或view时,需要用send,但尽量避免,因为要花钱啊!调用用例:

myContract.methods.yourWantMethod(123).send()

                      相比call函数,send一个事务需要一个from来表明谁在调用这个函数(对呀solidity的msg.sender),这样metamask才会弹出提示让他们对事务签名。因为send是要写到区块链中的,所以在用户send到事务被包含进区块之前有一个不可忽略的延迟,所以这里需要异步处理。示例:

function createRandomZombie(name) {
  // 这将需要一段时间,所以在界面中告诉用户这一点
  // 事务被发送出去了
  $("#txStatus").text("正在区块链上创建僵尸,这将需要一会儿...");
  // 把事务发送到我们的合约:
  return cryptoZombies.methods.createRandomZombie(name)
  .send({ from: userAccount })
  .on("receipt", function(receipt) {
    $("#txStatus").text("成功生成了 " + name + "!");
    // 事务被区块链接受了,重新渲染界面
    getZombiesByOwner(userAccount).then(displayZombies);
  })
  .on("error", function(error) {
    $("#txStatus").text(error);
  });
}

            一些关于send函数的补充 :

//receipt在合约被包含进区块后触发
//error在事务未被包含进以太坊上触发
//可以在调用send的时候指定gas和gasprice
.send({from: userAccount, gas: 300000});
// 同时send中发送的应该是以wei为单位发送,1ether等于10^18wei,转换方法如下
web3js.utils.toWei("1","ether");
//在send函数中
.send({ from: userAccount, value: web3js.utils.toWei("0.001","ether") })

3.事件监听   

   直接看代码就明白了:

//假设你的目标合约中定义了一个事件监听叫做NewZombie;
cryptoZombies.events.NewZombie()
.on("data", function(event) {
  let zombie = event.returnValues;
  console.log("一个新僵尸诞生了!", zombie.zombieId, zombie.name, zombie.dna);
}).on('error', console.error);

3.1 indexed关键字的用法   

      可以看成是一个过滤字段,用于筛选仅和当前用户有关的字段。用例:

//合约里有如下transfer事件
event Transfer(address indexed _from, address indexed _to, uint256 _tokenId);

//监听该事件,过滤掉只要 userAccount
cryptoZombies.events.Transfer({ filter: { _to: userAccount } })
.on("data", function(event) {
  let data = event.returnValues;
  // 当前用户更新!更新界面来显示
}).on('error', console.error);

 3.2 查询过去的事件 getPastEvents(fromBlock,toBlock)。block指以太坊区块编号

cryptoZombies.getPastEvents("NewZombie", { fromBlock: 0, toBlock: 'latest' })
.then(function(events) {
  // events 是可以用来遍历的 `event` 对象 
});
  • 以上,你知道了web3.js怎么去调合约。

  •  参考文献: 

    • https://share.cryptozombies.io/zh/lesson/6/chapter/1 一个非常不错的入门教程

    • http://web3.tryblockchain.org/Web3.js-api-refrence.html Web3.js API中文文档          

 

你可能感兴趣的:(Dapp开发)