web3.js官方文档:https://web3js.readthedocs.io/en/v1.2.11/index.html

 

web3.js开源文库(github):https://github.com/ethereum/web3.js

 

 在我的以太坊手机轻钱包开发javascript签名合约交易这篇文章中我已经写到了如何用web3.js发布合约

接下来我们将使用web3.js与现有合约交互,下面合约也是以太坊....javascript签名合约交易这篇文章使用的合约案例.如果您目前没有部署下面合约,你可以参考这边文章部署好合约.,然后按步骤实操.

 

 

 

 

示例合约

本文以下面的MetaCoin合约为例,说明在应用中使用web3.js操作智能合约的方法。

 
  1. // 本文中用到的MetaCoin合约

  2. pragma solidity ^0.4.2;

  3.  
  4. contract MetaCoin {

  5. mapping (address => uint) balances;

  6.  
  7. event Transfer(address indexed _from, address indexed _to, uint256 _value);

  8.  
  9. function MetaCoin() {

  10. balances[msg.sender] = 10000;

  11. }

  12.  
  13. function sendCoin(address receiver, uint amount) returns(bool sufficient) {

  14. if (balances[msg.sender] < amount) return false;

  15. balances[msg.sender] -= amount;

  16. balances[receiver] += amount;

  17. Transfer(msg.sender, receiver, amount);

  18. return true;

  19. }

  20.  
  21. function getBalance(address addr) returns(uint) {

  22. return balances[addr];

  23. }

  24.  

 

这个合约有三个函数:

MetaCoin:构造函数,在合约被部署到区块链时执行 
getBalance:返回某账户的余额,它只读数据,不会修改数据 
sendCoin:向另一个账户发送指定数量的MetaCoin,它会改变状态变量balances 

创建web3对象

要使用web3.js与区块链交互,需要先创建web3对象,然后连接到以太坊节点

 

 

  1.     // 创建web3对象

  2. var web3 = new Web3();

  3. // 连接到以太坊节点

  4. web3.setProvider(new Web3.providers.HttpProvider("http://localhost:8545"));

 

 

 

获取已部署的合约实例

 

要使用智能合约,必须先从区块链中获取到合约实例,获取合约实例需要合约的ABI和合约的地址:

 
  1. // 合约ABI

  2. var abi = [{"constant":false,"inputs":[{"name":"receiver","type":"address"},{"name":"amount","type":"uint256"}],"name":"sendCoin","outputs":[{"name":"sufficient","type":"bool"}],"payable":false,"type":"function"},{"constant":false,"inputs":[{"name":"addr","type":"address"}],"name":"getBalance","outputs":[{"name":"","type":"uint256"}],"payable":false,"type":"function"},{"inputs":[],"payable":false,"type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"name":"_from","type":"address"},{"indexed":true,"name":"_to","type":"address"},{"indexed":false,"name":"_value","type":"uint256"}],"name":"Transfer","type":"event"}];

  3. // 合约地址

  4. var address = "0xb2cdd356e58280906ce53e1665697b50f88aac56";

  5. // 通过ABI和地址获取已部署的合约对象

  6. var metacoin = web3.eth.contract(abi).at(address);

 

metacoin就是获取到的合约对象实例,此时metacoin对象中就包含了与合约函数同名的Javascript函数,之后就可以通过metacoin对象来调用合约中的函数了。

 

调用合约函数

MetaCoin合约中有两个函数:getBalance和sendCoin,可以通过metacoin对象直接调用这两个函数。

首先来看getBalance,由于getBalance函数只是从区块链中读数据,而不修改数据,因此我们通过在getBalance后面加上.call()的方式调用:

 
  1. var account_one = web3.eth.accounts[0];

  2. var account_one_balance = metacoin.getBalance.call(account_one);

  3. console.log("account one balance: ", account_one_balance.toNumber());

这里:

 

在getBalance后加上.call()来显式指明用call的方式调用 
通过call的方式调用可以得到getBalance函数的返回值 
通过call的方式调用的函数只在节点本地虚拟机中执行,不会产生交易,不会花费费用,不会修改数据 
下面来看sendCoin函数,由于sendCoin要修改合约内部的数据,所以要使sendCoin生效,必须要向区块链发送交易,可以在sendCoin后面加上.sendTransaction()来指明这是一笔交易:

 
  1. var account_one = web3.eth.accounts[0];

  2. var account_two = web3.eth.accounts[1];

  3. // 提交交易到区块链,会立即返回交易hash,但是交易要等到被矿工收录到区块中后才生效

  4. var txhash = metacoin.sendCoin.sendTransaction(account_two, 100, {from:account_one});

这里:

 

在sendCoin函数后加上.sendTransaction()指明要向区块链发送交易 
合约代码中sendCoin函数只有两个参数,而在web3中通过.sendTransaction()调用合约函数的时候需要增加最后一个参数,它是一个javascript对象,里面可以指定from/value/gas等属性,上面的例子用from来指定交易的发送者 
上面的调用语句执行后,会向区块链提交一笔交易,这笔交易的发送者是account_one,接收者是metacoin的地址,交易的作用是以account_two和100作为参数执行合约的sendCoin函数 
函数会立即返回交易的hash,表明交易已经提交到区块链,但是并不知道交易何时处理完成,交易要等到被旷工收录到区块中后才会生效 
监听合约事件

当通过.sendTransaction()调用合约的时候,交易会被提交到区块链进行处理,这个处理需要一定的时间,如果需要等交易完成之后再执行其他操作,就必须要知道交易何时完成,那么如何知道交易何时完成呢?可以通过监听合约事件来实现。

在合约中可以定义事件,事件可以带有参数,在合约函数内部完成某些操作时,可以触发事件,向外界传达一些信息。例如,在MetaCoin合约中定义了一个事件叫做Transfer,表示一个转账的事件,它带有三个参数:交易的发送者、接受者、转账数量。在sendCoin函数中,转账成功后就会触发Transfer事件,将对应的参数传给该事件,这样外部监听到事件后,可以取出事件的参数来获得交易发送者、接收者、数量。同时事件中还带有其他信息,比如交易hash等。

在web3中使用事件,要首先获取事件对象,然后监听事件,如果事件发生,就会在回调函数中获取到事件信息:

 
  1. // 获取事件对象

  2. var myEvent = metacoin.Transfer();

  3. // 监听事件,监听到事件后会执行回调函数

  4. myEvent.watch(function(err, result) {

  5. if (!err) {

  6. console.log(result);

  7. } else {

  8. console.log(err);

  9. }

  10. myEvent.stopWatching();

  11. });

  12.  
  13. // 输出:

  14. { address: '0xb2cdd356e58280906ce53e1665697b50f88aac56',

  15. blockNumber: 651,

  16. transactionIndex: 0,

  17. transactionHash: '0xcc71bc2824cc84d1ee831c46189e3a80cf0af05697ba0370693aa97390c8067b',

  18. blockHash: '0x1d53f04206f3926d0f311b1230a9dd0b0c5aadac35b169a6a609e384ab130c6f',

  19. logIndex: 0,

  20. removed: false,

  21. event: 'Transfer',

  22. args:

  23. { _from: '0x68b73956d704007514e9257813bdc58cdf3c969a',

  24. _to: '0x9c3c1a2f5ef913fac44f0348a78f68d835f3f26e',

  25. _value: { [String: '100'] s: 1, e: 2, c: [Object] } } }

  1.  

从输出可以看出,获取到的事件信息包括事件的参数、事件名、区块号、交易hash等。

 

通过检测事件中的transactionHash与调用合约函数返回的交易hash是否一致,可以判定某一笔交易是否已完成:

 
  1. var account_one = web3.eth.accounts[0];

  2. var account_two = web3.eth.accounts[1];

  3.  
  4. var account_one_balance = metacoin.getBalance.call(account_one);

  5. console.log("account one balance:", account_one_balance.toNumber());

  6.  
  7. var txhash = metacoin.sendCoin.sendTransaction(account_two, 100, { from: account_one });

  8.  
  9. var myEvent = metacoin.Transfer();

  10. myEvent.watch(function (err, result) {

  11. if (!err) {

  12. if (result.transactionHash == txhash) {

  13. var account_one_balance = metacoin.getBalance.call(account_one);

  14. console.log("account one balance after sendCoin:", account_one_balance.toNumber());

  15. }

  16. } else {

  17. console.log(err);

  18. }

  19. myEvent.stopWatching();

  20. });

  21.  
  22. // 输出:

  23. account one balance: 7000

  24. account one balance after sendCoin: 6900

Logo

为所有Web3兴趣爱好者提供学习成长、分享交流、生态实践、资源工具等服务,作为Anome Land原住民可不断优先享受各种福利,共同打造全球最大的Web3 UGC游戏平台。

更多推荐