ethers.js2:provider提供商

news/2024/7/7 14:34:49 标签: 区块链, 智能合约

1、Provider

Provider类是对以太坊网络连接的抽象,为标准以太坊节点功能提供简洁、一致的接口。在ethers中,Provider不接触用户私钥,只能读取链上信息,不能写入,这一点比web3.js要安全。

除了之前介绍的默认提供者defaultProvider以外,ethers中最常用的是jsonRpcProvider,可以让用户连接到特定节点服务商的节点。

jsonRpcProvider

2、创建节点服务商的API Key

首先,需要去节点服务商的网站注册并创建API Key,有Infura和Alchemy两家公司API Key的创建方法。

Infura API Key

Infura API Key

3、连接Infura节点 

我们用Infura节点作为例子。在创建好Infura API Key之后,就可以利用ethers.provider.JsonRpcProvider()方法来创建Provider变量。JsonRpcProvider()以节点服务的url作为参数。

 在下面这个例子中,我们分别创建连接到ETH主网和Goerli测试网的provider

// 利用Infura的rpc节点连接以太坊网络
// 填入Infura API Key, 教程:https://github.com/AmazingAng/WTFSolidity/blob/main/Topics/Tools/TOOL02_Infura/readme.md
const INFURA_ID = ''
// 连接以太坊主网
const providerETH = new ethers.providers.JsonRpcProvider(`https://mainnet.infura.io/v3/${INFURA_ID}`)
// 连接Goerli测试网
const providerGoerli = new ethers.providers.JsonRpcProvider(`https://goerli.infura.io/v3/${INFURA_ID}`)

4、利用Provider读取链上数据

Provider类封装了一些方法,可以便捷的读取链上数据:

1. 利用getBalance()函数读取主网和测试网V神的ETH余额:

    // 1. 查询vitalik在主网和Goerli测试网的ETH余额
    console.log("1. 查询vitalik在主网和Goerli测试网的ETH余额");
    const balance = await providerETH.getBalance(`vitalik.eth`);
    const balanceGoerli = await providerGoerli.getBalance(`vitalik.eth`);
    // 将余额输出在console(主网)
    console.log(`ETH Balance of vitalik: ${ethers.utils.formatEther(balance)} ETH`);
    // 输出Goerli测试网ETH余额
    console.log(`Goerli ETH Balance of vitalik: ${ethers.utils.formatEther(balanceGoerli)} ETH`);

V神余额

 2. 利用getNetwork()查询provider连接到了哪条链,homestead代表ETH主网:

  // 2. 查询provider连接到了哪条链
    console.log("\n2. 查询provider连接到了哪条链")
    const network = await providerETH.getNetwork();
    console.log(network);

getNetwork

 3. 利用getBlockNumber()查询当前区块高度:

    // 3. 查询区块高度
    console.log("\n3. 查询区块高度")
    const blockNumber = await providerETH.getBlockNumber();
    console.log(blockNumber);

getBlockNumber

 4. 利用getGasPrice()查询当前gas price,返回的数据格式为BigNumber,可以用BigNumber类的toNumber()toString()方法转换成数字和字符串。

    // 4. 查询当前gas price
    console.log("\n4. 查询当前gas price")
    const gasPrice = await providerETH.getGasPrice();
    console.log(gasPrice);

getGasPrice

5. 利用getFeeData()查询当前建议的gas设置,返回的数据格式为BigNumber

    // 5. 查询当前建议的gas设置
    console.log("\n5. 查询当前建议的gas设置")
    const feeData = await providerETH.getFeeData();
    console.log(feeData);

getFeeData

6. 利用getBlock()查询区块信息,参数为要查询的区块高度:

    // 6. 查询区块信息
    console.log("\n6. 查询区块信息")
    const block = await providerETH.getBlock(0);
    console.log(block);

getBlock

 7. 利用getCode()查询某个地址的合约bytecode,参数为合约地址,下面例子中用的主网WETH的合约地址:

    // 7. 给定合约地址查询合约bytecode,例子用的WETH地址
    console.log("\n7. 给定合约地址查询合约bytecode,例子用的WETH地址")
    const code = await providerETH.getCode("0xc778417e063141139fce010982780140aa0cd5ab");
    console.log(code);

getCode

完整代码:

{/* <script src="https://cdn.ethers.io/lib/ethers-5.6.9.min.js"></script> */}
const ethers = require("ethers");
// import { ethers } from "ethers";
// import { ethers } from "https://cdn-cors.ethers.io/lib/ethers-5.6.9.esm.min.js";

const INFURA_ID = '012dac20ba9f43c0ad4fd8be46ae2c37';

const providerETH = new ethers.providers.JsonRpcProvider('https://mainnet.infura.io/v3/012dac20ba9f43c0ad4fd8be46ae2c37');
const providerGeorli = new ethers.providers.JsonRpcProvider('https://goerli.infura.io/v3/012dac20ba9f43c0ad4fd8be46ae2c37');

const main = async () => {
    //查询vitalik在主网和georli上的eth余额
    console.log('1、查询vitalik的ETH余额');
    const balanceETH = await providerETH.getBalance('vitalik.eth');
    const balanceGeorliETH = await providerGeorli.getBalance('vitalik.eth');
    console.log('ETH balance of vitalik:' + ethers.utils.formatEther(balanceETH) +'ETH' );
    console.log('GeorliETH balance of vitalik:' + ethers.utils.formatEther(balanceGeorliETH) + 'ETH');

    console.log('\n 2、查询现在是哪条链');
    const network = await providerETH.getNetwork();
    console.log(network);

    console.log('\n 3、查询当前区块高度');

    const blockNum = await providerETH.getBlockNumber();
    console.log(blockNum);

    console.log('\n 4、查询当前gasPrice');
    const gasPrice = (await providerETH.getGasPrice()).toString();
    console.log(gasPrice);

    console.log('\n5、查询当前区块信息');
    const blockInfo = await providerETH.getBlock(17969422);
    console.log(blockInfo);

    console.log('\n6、查询某个合约地址的代码字节码');
    const bytecode = await providerETH.getCode('0x1f9840a85d5aF5bf1D1762F925BDADdC4201F984');
    console.log(bytecode);

};

main()

总结

ethers.js的Provider类,并用Infura的节点API Key创建了jsonRpcProvider,读取了ETH主网和Goerli测试网的链上信息。 

踩坑记录:

运行后仍然跟上一次一样报错:

import { ethers } from "https://cdn-cors.ethers.io/lib/ethers-5.6.9.esm.min.js";
^^^^^^

SyntaxError: Cannot use import statement outside a module
    at internalCompileFunction (node:internal/vm:74:18)
    at wrapSafe (node:internal/modules/cjs/loader:1141:20)
    at Module._compile (node:internal/modules/cjs/loader:1182:27)
    at Module._extensions..js (node:internal/modules/cjs/loader:1272:10)
    at Module.load (node:internal/modules/cjs/loader:1081:32)
    at Module._load (node:internal/modules/cjs/loader:922:12)
    at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:81:12)
    at node:internal/main/run_main_module:23:47

Node.js v18.13.0

原因是,在一个非模块化的环境中使用了ES6的 import 语句,导致了错误。代码运行在普通的JavaScript环境中,而不是模块化环境,您可以将 import 语句替换为传统的脚本引入方式。将以下代码:

import { ethers } from "ethers";

替换为:

const ethers = require("ethers");

另外再修改原来代码中的一些错误写法,比如少一个括号,把$去掉等。

就可以正常运行并得到结果:

ETH balance of vitalik:3933.795127185004997518ETH

2、报错:

const network = await ethers.providerETH.getNetwork(); 
                                             ^ 
 
TypeError: Cannot read properties of undefined (reading 'getNetwork') 

 在const network = await ethers.providersETH.getNetwork();中语法错误,改为:

const network = await providersETH.getNetwork();
即可解决。

3、报错:

console.log('\n 4、查询当前gasPrice');

    const gasPrice = (await providerETH.getGasPrice()).toString;

    console.log(gasPrice);

};


运行结果是:

[Function (anonymous)]

因为在代码中,toString我少写了一个括号,应该是:

    const gasPrice = (await providerETH.getGasPrice()).toString;

另外,有一次我的代码是:

console.log('\n 4、查询当前gasPrice');

    const gasPrice = await providerETH.getGasPrice().toString();

    console.log(gasPrice);

};

运行得到的结果是:

undefined
原因是,const gasPrcie = await providerETH.getGasPrice().toString().要改为:
 

const gasPrcie = (await providers.getGasPrice()).toString();


http://www.niftyadmin.cn/n/4965666.html

相关文章

Tokenview再度升级:全新Web3开发者APIs数据服务体验!

Tokenview发布全新版本的区块链APIs和数据服务平台&#xff0c;为开发者打造更强大、更便捷的开发体验&#xff01; 此次升级&#xff0c;我们整合了开发者使用习惯以及Tokenview产品优势。我们深知对于开发者来说&#xff0c;时间是非常宝贵的&#xff0c;因此我们努力提供一…

Java面试题—2023年8月24日—YDZH

2023-08-24 10:54:28 北京 yī do zh h 答案仅供参考&#xff0c;博主仅记录发表&#xff0c;没有实际查询&#xff0c;不保证正确性。 面试题&#xff1a; 1、请你谈谈关于 Synchronized 和 lock ? 2、请简单描述一下类的加载过程?类加载器有几个种&#xff0c;分别作用是什…

【音视频】 视频的播放和暂停,当播放到末尾时触发 ended 事件,循环播放,播放速度

video 也可以 播放 MP3 音频&#xff0c;当不想让 视频显示出来的话&#xff0c;可以 给 video 设置宽和高 1rpx &#xff0c;不可以隐藏 <template><view class"form2box"><u-navbar leftClick"leftClick"><view slot"left&q…

深入理解 Vue Router:构建可靠的前端路由系统

目录 01-什么是前端路由以及路由两种模式实现原理02-路由的基本搭建与嵌套路由模式03-动态路由模式与编程式路由模式04-命名路由与命名视图与路由元信息05-路由传递参数的多种方式及应用场景06-详解route对象与router对象07-路由守卫详解及应用场景 01-什么是前端路由以及路由两…

第8章 海量数据搜索实现

mini商城第8章 海量数据搜索实现 一、课题 海量数据搜索 二、回顾 1、理解OpenResty 百万并发站点架构 2、能明白多级缓存架构思路 3、实现Nginx代理缓存 4、能实现缓存一致性 三、目标 1、了解ElasticSearch并会使用核心API 2、基于Canal实现ES和数据库数据同步 3、…

在router中使用pinia、在组件外使用pinia时 报错没有激活pinia

getActivePinia was called with no active Pinia. Did you forget to install pinia? 我想在路由守卫中使用store中部的数据&#xff0c;但是拿不到仓库&#xff0c;提示pinia没激活 解决方案&#xff1a;借鉴vben-admin 在每个模块中都把pinia和当前的仓库绑定一份暴漏出去…

非凸联合创始人李佐凡受邀出席复旦DSBA项目座谈会

8月17日&#xff0c;非凸科技联合创始人&CTO李佐凡受邀参加复旦管院数据科学与商业分析专业硕士&#xff08;DS&BA&#xff09;项目发展座谈会&#xff0c;与学校教授、老师在生源背景、课程教学、职业发展、学生培养和企业合作方面进行深入交流&#xff0c;旨在更好地…

ROS功能包目录下CMakeLists.txt

1. add_execuble CMake基础教程&#xff08;24&#xff09;add_executable生成目标可执行文件 CMake中add_executable的使用 CMake中的add_executable命令用于使用指定的源文件向项目(project)添加可执行文件&#xff0c;其格式如下&#xff1a; add_executable(<name>…