Web3.js 常用方法汇总

3,066 阅读12分钟

web3.js 官方文档 :web3js.readthedocs.io/en/v1.8.0/

Metamask 官方文档: docs.metamask.io/guide/

一、引入web3.js

方式一: npm install web3

方式二:引入 dist/web3.min.js 文件

二、常用方法汇总

1、Web3 浏览器检测

大多数支持以太坊的浏览器(例如 MetaMask)在 window.ethereum 上都有一个符合 EIP-1193 的提供程

if (typeof window.ethereum !== 'undefined') {
  console.log('MetaMask is installed!');
  // 未安装可以提示用户并新页面打开Metamask 安装网址
  window.open('https://metamask.io/download/');  // 打开Metamask 安装页面
}

2、创建Web3实例并设置Provider

const Web3 = require('web3')
const web3 = new Web3(Web3.givenProvider || "ws://localhost:8545");
// Web3.givenProvider 当前环境的原生 provider 会被浏览器设置
// web3.givenProvider 将返回浏览器设置的原生 provider 集,返回 null 再连接本地或远程的节点
// 连接到远程节点
var web3 = new Web3("https://eth-mainnet.alchemyapi.io/v2/your-api-key");

更改Provider

// change provider
web3.setProvider('ws://localhost:8546');
// or
web3.setProvider(new Web3.providers.WebsocketProvider('ws://localhost:8546'));

3、检查网络状况

const Web3 = require('web3')
const web3 = new Web3(Web3.givenProvider || "ws://localhost:8545");
// 判断网络是否连接
let isConnecting =  web3.eth.net.isListening();  // 返回结果为布尔值
//  判断当前连接网络类型
let netId =  web3.eth.net.getId();  // 返回当前链接网络链id

4、添加网络(wallet_addEthereumChain)

  window.ethereum &&
      window.ethereum
        .request({
          method: 'wallet_addEthereumChain',
          params: [
            {
              chainId: 97,
              chainName:  'Binance Smart Chain Testnet',
              nativeCurrency: {
                name: 'BNB',
                symbol: 'BNB',
                decimals: 18,
              },
              rpcUrls:'https://bsc-dataseed1.binance.org/',
              blockExplorerUrls:  'https://bscscan.com/',
            },
          ],
        })

5、切换网络(wallet_switchEthereumChain)

 window.ethereum && window.ethereum
   .request({
     method: 'wallet_switchEthereumChain',
       params: [
        {
           chainId: 97
        },
      ],
   })

6、链接钱包 requestAccounts

此方法将从当前环境请求/启用帐户。 此方法仅在您使用来自 Metamask、Status 或 TrustWallet 等应用程序的注入提供程序时才有效。 如果您连接到具有默认 Web3.js 提供程序(WebsocketProvider、HttpProvider 和 IpcProvider)的节点,则它不起作用。

let accounts =  web3.eth.requestAccounts();
// 入参 Function -(可选)可选回调,返回错误对象作为第一个参数,结果作为第二个参数。
// 返回启用账户的数组 

/* 等同于*/
const onClickConnect = async () => {
  try {
    let account = await ethereum.request({ method: 'eth_requestAccounts' });
  } catch (error) {
    console.error(error);
  }
};

连接到用户后,可以通过检查 window.ethereum.selectedAddress 重新检查当前帐户.

切换账户监听事件

连接钱包账户切换后触发的事件;

ethereum.on('accountsChanged', (accounts) => {
  console.log("accounts",accounts)
});

切换网络监听事件

ethereum.on('chainChanged', (chainId) => {
  // 正确处理链更改之后的业务流程可能很复杂。官方建议链更改只有重新加载页面
  console.log("chainId",chainId)
  window.location.reload();
});

断开连接监听事件

ethereum.on('disconnect',  async function (result, error) {
  console.log("result",result)
  console.log("error",error)
 });

7、获取当前链ID getChainId

可以用于检测用户连接到哪个以太坊网络

“已连接”这个词,指的是 web3 站点是否可以访问用户的帐户。 然而,在提供者接口中,“已连接”和“已断开”是指提供者是否可以向当前链发出 RPC 请求。

let eth_chainId = web3.eth.getChainId();
console.log("eth_chainId",eth_chainId)
// 示例
let accounts = await this.web3.eth.requestAccounts();
let eth_chainId = await this.web3.eth.getChainId();
console.log("查询eth_chainId", eth_chainId)
if (eth_chainId !== configs.chainId) {  // 与当前
   message.warning('Please switch to the Binance Smart Chain Mainnet')
  // 此处可调用切换网络方法,切换到正确网络
   return;
}

8、签名方法 汇总

  • eth_sign (insecure and unadvised to use) 不安全不建议使用
  • personal_sign
  • signTypedData (currently identical to signTypedData_v1)(与 signTypedData_v1 相同)
  • signTypedData_v1
  • signTypedData_v3
  • signTypedData_v4 (最新EIP-712 规范的版本)

personal_sign

web3.eth.personal.sign(dataToSign, address, password [, callback])

入参:

1.字符串 - 要签名的数据。 如果是字符串,它将使用 web3.utils.utf8ToHex 进行转换。

  1. 字符串 - 用于签署数据的地址。

  2. 字符串 - 用于签署数据的帐户的密码。可以不传

  3. Function - (可选)可选回调,第一个参数返回错误对象,第二个参数返回结果。

返回:字符串类型的签名凭证

web3.eth.personal.sign(web3.utils.utf8ToHex("Hello world"), "0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe", "test password!")
.then(console.log);
> "0x30755ed65396facf86c53e6217c52b4daebe72aa4941d89635409de4c9c7f9466d4e9aaec7977f05e923889b33c0d0dd27d7226b6e6f56ce737465c5cfd04be400"
/* 等同于 */
let selectedAccount = '0x4265c9e28C4305789232813c80cfD8d0757a8149'
let msg = 'hello Web3 !'
const signature = web3.eth.personal.sign(msg, selectedAccount);
console.log("signature",signature)

signTypedData_v4

符合最新EIP712标准的签名方式,交易相关签名建议使用这种方式

   let msgParams = createSignMessage(msg);
   let params = [from, msgParams];
   let method = "eth_signTypedData_v4";
    console.log("msgParams===============", JSON.parse(msgParams));
    web3.currentProvider.sendAsync(
      {
        method,
        params,
        from: from,
      },
      function (err, result) {
        if (err) {
          console.log("err", err);
          message.error(err.message);
          resolve(false);
        }
        if (result.error) return console.error("ERROR", result);
        console.log("TYPED SIGNED:" + JSON.stringify(result.result));
        let signData = JSON.stringify(result.result);
        resolve(signData);
      }
    );

详细参考文档 见:

www.yuque.com/zhouxingyu-…

docs.metamask.io/guide/signi…

9、余额查询 getBalance

getBalance 方法可以获取给定区块的地址余额。

web3.eth.getBalance(address [, defaultBlock] [, callback])
// defaultBlock 参数可选,如果传递此参数,它将不使用 web3.eth.defaultBlock 设置的默认块。
// 也可以使用预定义的块编号,如“最早”、“最新”、“待定”、“安全”或“最终”。
// 示例
web3.eth.getBalance("0x407d73d8a49eeb85d32cf465507dd71d507100c1")
.then(console.log);
> "1000000000000"

10、交易查询 getTransaction

web3.eth.getTransaction(transactionHash [, callback])

参数:

  • transactionHash:String - 交易的哈希值
  • callback:Function - 可选的回调函数,其第一个参数为错误对象,第二个参数为返回结果。

返回值:

一个Promise对象,其解析值为具有给定哈希值的交易对象,该对象具有如下字段:

  • hash 32 Bytes - String: 交易的哈希值
  • nonce - Number: 交易发送方在此交易之前产生的交易数量
  • blockHash 32 Bytes - String: 交易所在块的哈希值。如果交易处于pending状态,则该值为null
  • blockNumber - Number: 交易所在块的编号,如果交易处于pending状态,则该值为null
  • transactionIndex - Number: 交易在块中的索引位置,如果交易处于pending状态,则该值为null
  • from - String: 交易发送方的地址
  • to - String: 交易接收方的地址。对于创建合约的交易,该值为null
  • value - String: 以wei为单位的转账金额
  • gasPrice - String: 发送方承诺的gas价格,以wei为单位
  • gas - Number: 发送方提供的gas用量
  • input - String: 随交易发送的数据
web3.eth.getTransaction('0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b§234')
.then(console.log);
> {
    "hash": "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b",
    "nonce": 2,
    "blockHash": "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46",
    "blockNumber": 3,
    "transactionIndex": 0,
    "from": "0xa94f5374fce5edbc8e2a8697c15331677e6ebf0b",
    "to": "0x6295ee1b4f6dd65047762f924ecd367c17eabf8f",
    "value": '123450000000000000',
    "gas": 314159,
    "gasPrice": '2000000000000',
    "input": "0x57cb2fc4"
}

11、发送交易 sendTransaction

const transactionParameters = {
  nonce: '0x00', // ignored by MetaMask
  gasPrice: '0x09184e72a000', // customizable by user during MetaMask confirmation.
  gas: '0x2710', // customizable by user during MetaMask confirmation.
  to: '0x0000000000000000000000000000000000000000', // Required except during contract publications.
  from: ethereum.selectedAddress, // must match user's active address.
  value: '0x00', // Only required to send ether to the recipient from the initiating external account.
  data:
    '0x7f7465737432000000000000000000000000000000000000000000000000000000600057', // Optional, but used for defining smart contract creation and interaction.
  chainId: '0x3', // Used to prevent transaction reuse across blockchains. Auto-filled by MetaMask.
};

// txHash is a hex string
// As with any RPC call, it may throw an error
const txHash = await ethereum.request({
  method: 'eth_sendTransaction',
  params: [transactionParameters],
});

三、合约相关方法

1、初始化合约对象

new web3.eth.Contract(jsonInterface[, address][, options])

创建一个新的合约实例,其所有方法和事件都在其 json 接口对象中定义。

入参:

  • jsonInterface - Object:合约实例化的json接口
  • address - 字符串(可选):要调用的智能合约的地址。
  • options - 对象(可选):合约的选项。 有些用作调用和事务的后备:
  • from - 字符串:应从地址进行交易。
  • gasPrice - 字符串:用于交易的以 wei 为单位的 gas 价格。
  • gas - Number:为交易提供的最大 gas(gas 限制)。
  • data - String:合约的字节码。 在部署合约时使用。

返回:

  • 对象:合约实例及其所有方法和事件。
var MyContract = new web3.eth.Contract(abi,address)

// 具体使用示例
const ProxyRegistryAddress = "0x392431428a1CEAcC4022C8E86eBb73Ed4bf2EFa6"; // 用户注册合约地址
const registerAbi = [...省略json 接口文件] // 合约实例化的ABI json接口
// 初始化合约对象
const initAllContact = () => {
  let web3 =  Web3Manager.getWeb3Ins(); // 获取web 实例对象
  let ProxyRegistryContact = new web3.eth.Contract(
    RegisterAbi,
    ProxyRegistryAddress
  );
};

2、Call 调用合约方法

myContract.methods.myMethod([param1[, param2[, ...]]]).call(options [, defaultBlock] [, callback])

  • myMethod 为合约内部定义的具体方法名;
  • [param1[, param2[, ...]]] 为合约定义的方法所需要的参数;

参数:

options - Object(可选):调用的参数选项

  • from - 字符串(可选):调用事件的地址,是可选的,但强烈建议设置它,否则默认为 address(0)
  • gasPrice - 字符串(可选):交易的以 wei 为单位的 gas 价格
  • gas - Number(可选):交易提供的最大 gas(gas 限制)

defaultBlock - Number|String|BN|BigNumber(可选):

如果您传递此参数,它将不使用通过 contract.defaultBlock 设置的默认块。也可以使用预定义的块编号,如"earliest", "latest", "pending", "safe" or "finalized" 作为参数。用于从过去的区块中请求数据或重放交易。

callback - 函数(可选):此回调的第一个参数为err,第二个参数为智能合约方法执行的结果result

// 判断用户是否注册 || 查询用户的代理合约地址
let walletAddress = '0x4265c9e28C4305789232813c80cfD8d0757a8149'
const isRegister = () => {
  let { ProxyRegistryContact } = initAllContact();  //  初始化合约
  return new Promise((resolve, reject) => {
    ProxyRegistryContact.methods
      .proxies(walletAddress)
      .call((err, result) => {
        if (result) {
          resolve(result);
        }
        if (err) {
          message.error(err);
          reject(err)
        }
      });
  })
};

3、 Send 发送合约方法交易

myContract.methods.myMethod([param1[, param2[, ...]]]).send(options[, callback])

  • myMethod: 合约内部定义的具体方法名;
  • [param1[, param2[, ...]]] :合约内部方法所需要的参数;

入参:

options - Object:发送交易的参数选项。

  • from - 字符串:交易的发送地址。
  • gasPrice - 字符串(可选):用于此交易的以 wei 为单位的 gas 价格。
  • gas - Number(可选):为此交易提供的最大 gas(gas 限制)。
  • value - Number|String|BN|BigNumber(可选):为交易传输的价值,以 wei 为单位。
  • nonce - Number(可选):交易的随机数

callback - 函数(可选):返回transactionHash 交易哈希,或者错误对象回调;

返回:

回调函数中将返回32字节长的交易哈希值。

PromiEvent: 一个Promise对象,当交易收据有效时或者发送交易时解析为新的合约实例。 它同时也是一个事件发生器,声明有以下事件:

  • "transactionHash" 返回 String: 交易发送后得到有效交易哈希值时触发
  • "receipt" 返回 Object: 交易收据有效时触发。
  • "confirmation" 返回 Number, Object: 收到确认时触发
  • "error" 返回 Error: 交易发送过程中如果出现错误则触发此事件。对于out of gas错误,其第二个参数为交易收据

myContract.methods.myMethod(123).send({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'})
.on('transactionHash', function(hash){
    console.log("hash",hash) 
  // 返回string 类型的交易hash,交易发送后得到有效交易哈希值时触发 
})
.on('confirmation', function(confirmationNumber, receipt,latestBlockHash){
// 发送的交易被确认时触发,返回 confirmationNumber 和 回执对象,latestBlockHash 最新区块hash
})
.on('receipt', function(receipt){ //  交易收据有效时触发,返回一个Object对象
    // receipt example
    console.log(receipt);  // 返回的回执示例
    > {
        "transactionHash": "0x9fc76417374aa880d4449a1f7f31ec597f00b1f6f3dd2d66f4c9c6c445836d8b",
        "transactionIndex": 0,
        "blockHash": "0xef95f2f1ed3ca60b048b4bf67cde2195961e0bba6f70bcbea9a2c4e133e34b46",
        "blockNumber": 3,
        "contractAddress": "0x11f4d0A3c12e86B4b5F39B213F7E19D048276DAe",
        "cumulativeGasUsed": 314159,
        "gasUsed": 30234,
        "events": {
            "MyEvent": {
                returnValues: {
                    myIndexedParam: 20,
                    myOtherIndexedParam: '0x123456789...',
                    myNonIndexParam: 'My String'
                },
                raw: {
                    data: '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385',
                    topics: ['0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7', '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385']
                },
                event: 'MyEvent',
                signature: '0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7',
                logIndex: 0,
                transactionIndex: 0,
                transactionHash: '0x7f9fade1c0d57a7af66ab4ead79fade1c0d57a7af66ab4ead7c2c2eb7b11a91385',
                blockHash: '0xfd43ade1c09fade1c0d57a7af66ab4ead7c2c2eb7b11a91ffdd57a7af66ab4ead7',
                blockNumber: 1234,
                address: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'
            },
            "MyOtherEvent": {
                ...
            },
            "MyMultipleEvent":[{...}, {...}] 
            // 如果有多个相同的事件,它们将在一个数组中
        }
    }
})
.on('error', function(error, receipt) { 
  // 如果交易被网络拒绝并带有收据,则第一个参数为error回调,第二个参数才是收据回执。
    
});
// 用户代币授权
// TokenContact 为代币合约  walletAddress 为用户钱包地址  defaultVal 为默认授权额度
// approve 为合约内部定义的授权方法,TokenTransferProxyAddress与defaultVal 为授权方法所需要的参数
const getAuthorization = (TokenContact, walletAddress) => {
  return new Promise((resolve, reject) => {
    let defaultVal = web3.utils.toWei("10000000000", "ether");
    TokenContact.methods
      .approve(TokenTransferProxyAddress, defaultVal)
      .send({ from: walletAddress })
      .on('receipt', function (receipt) {
        resolve(receipt.transactionHash)
      })
      .on('error', function (error, receipt) {
        message.error(error.message);
        resolve(false)
      })
  })
};

4、estimateGas - 估算合约方法gas用量

通过在EVM中执行方法来估算链上执行是需要的gas用量。得到的估算值可能与之后实际发送 交易的gas用量有差异,因为合约的状态可能在两个时刻存在差异。

调用:

myContract.methods.myMethod([param1[, param2[, ...]]]).estimateGas(options[, callback])

参数:

  • options - Object : 选项,包括以下字段:
    • from - String : 可选,交易发送方地址
    • gas - Number : 可选,本次交易gas用量上限
    • value - Number|String|BN|BigNumber: 可选,交易转账金额,单位:wei
    • callback - Function : 可选的回调函数,触发时其第二个参数为gas估算量,第一个参数为错误对象。

返回值:

一个Promise对象,其解析值为估算的gas用量。

// 使用回调函数
myContract.methods.myMethod(123).estimateGas({gas: 5000000}, function(error, gasAmount){
    if(gasAmount == 5000000)
        console.log('Method ran out of gas');
});

// 使用promise
myContract.methods.myMethod(123).estimateGas({from: '0xde0B295669a9FD93d5F28D9Ec85E40f4cb697BAe'})
.then(function(gasAmount){
    ...
})
.catch(function(error){
    ...
});