Skip to content

Files

Latest commit

0d50575 · Sep 25, 2023

History

History
This branch is 269 commits behind WTFAcademy/WTF-Ethers:main.

03_ReadContract

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
Aug 27, 2022
Apr 9, 2023
Sep 25, 2023
title tags
3. 读取合约信息
ethers
javascript
provider
contract
frontend
web

Ethers极简入门: 3. 读取合约信息

我最近在重新学ethers.js,巩固一下细节,也写一个WTF Ethers极简入门,供小白们使用。

推特@0xAA_Science

WTF Academy社群: 官网 wtf.academy | WTF Solidity教程 | discord | 微信群申请

所有代码和教程开源在github: github.com/WTFAcademy/WTF-Ethers


这一讲,我们将介绍Contract合约类,并利用它来读取链上的合约信息。

Contract

ethers中,Contract类是部署在以太坊网络上的合约(EVM字节码)的抽象。通过它,开发者可以非常容易的对合约进行读取call和交易transcation,并可以获得交易的结果和事件。以太坊强大的地方正是合约,所以对于合约的操作要熟练掌握。

创建Contract变量

只读和可读写Contract

Contract对象分为两类,只读和可读写。只读Contract只能读取链上合约信息,执行call操作,即调用合约中viewpure的函数,而不能执行交易transaction。创建这两种Contract变量的方法有所不同:

  • 只读Contract:参数分别是合约地址,合约abiprovider变量(只读)。
const contract = new ethers.Contract(`address`, `abi`, `provider`);
  • 可读写Contract:参数分别是合约地址,合约abisigner变量。Signer签名者是ethers中的另一个类,用于签名交易,之后我们会讲到。
const contract = new ethers.Contract(`address`, `abi`, `signer`);

注意 ethers中的call指的是只读操作,与solidity中的call不同。

读取合约信息

1. 创建Provider

我们使用Infura节点的API Key创建Provider(见第2讲:Provider):

import { ethers } from "ethers";
// 利用Infura的rpc节点连接以太坊网络
// 准备Infura API Key, 教程:https://github.com/AmazingAng/WTFSolidity/blob/main/Topics/Tools/TOOL02_Infura/readme.md
const INFURA_ID = ''
// 连接以太坊主网
const provider = new ethers.JsonRpcProvider(`https://mainnet.infura.io/v3/${INFURA_ID}`)

2. 创建只读Contract实例

创建只读Contract实例需要填入3个参数,分别是合约地址,合约abiprovider变量。合约地址可以在网上查到,provider变量上一步我们已经创建了,那么abi怎么填?

ABI (Application Binary Interface) 是与以太坊智能合约交互的标准,更多内容见WTF Solidity教程第27讲: ABI编码ethers支持两种abi填法:

  • 方法1. 直接输入合约abi。你可以从remix的编译页面中复制,在本地编译合约时生成的artifact文件夹的json文件中得到,或者从etherscan开源合约的代码页面得到。我们用这个方法创建WETH的合约实例:
// 第1种输入abi的方式: 复制abi全文
// WETH的abi可以在这里复制:https://etherscan.io/token/0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2#code
const abiWETH = '[{"constant":true,"inputs":[],"name":"name","outputs":[{"name":"","type":"string"}],"payable":false,"stateMutability":"view",...太长后面省略...';
const addressWETH = '0xc02aaa39b223fe8d0a0e5c4f27ead9083c756cc2' // WETH Contract
const contractWETH = new ethers.Contract(addressWETH, abiWETH, provider)

在Etherscan得到abi

  • 方法2. 由于abi可读性太差,ethers创新的引入了Human-Readable Abi(人类可读abi)。开发者可以通过function signatureevent signature来写abi。我们用这个方法创建稳定币DAI的合约实例:
// 第2种输入abi的方式:输入程序需要用到的函数,逗号分隔,ethers会自动帮你转换成相应的abi
// 人类可读abi,以ERC20合约为例
const abiERC20 = [
    "function name() view returns (string)",
    "function symbol() view returns (string)",
    "function totalSupply() view returns (uint256)",
    "function balanceOf(address) view returns (uint)",
];
const addressDAI = '0x6B175474E89094C44Da98b954EedeAC495271d0F' // DAI Contract
const contractDAI = new ethers.Contract(addressDAI, abiERC20, provider)

3. 读取WETHDAI的链上信息

我们可以利用只读Contract实例调用合约的viewpure函数,获取链上信息:

const main = async () => {
    // 1. 读取WETH合约的链上信息(WETH abi)
    const nameWETH = await contractWETH.name()
    const symbolWETH = await contractWETH.symbol()
    const totalSupplyWETH = await contractWETH.totalSupply()
    console.log("\n1. 读取WETH合约信息")
    console.log(`合约地址: ${addressWETH}`)
    console.log(`名称: ${nameWETH}`)
    console.log(`代号: ${symbolWETH}`)
    console.log(`总供给: ${ethers.formatEther(totalSupplyWETH)}`)
    const balanceWETH = await contractWETH.balanceOf('vitalik.eth')
    console.log(`Vitalik持仓: ${ethers.formatEther(balanceWETH)}\n`)

    // 2. 读取DAI合约的链上信息(IERC20接口合约)
    const nameDAI = await contractDAI.name()
    const symbolDAI = await contractDAI.symbol()
    const totalSupplDAI = await contractDAI.totalSupply()
    console.log("\n2. 读取DAI合约信息")
    console.log(`合约地址: ${addressDAI}`)
    console.log(`名称: ${nameDAI}`)
    console.log(`代号: ${symbolDAI}`)
    console.log(`总供给: ${ethers.formatEther(totalSupplDAI)}`)
    const balanceDAI = await contractDAI.balanceOf('vitalik.eth')
    console.log(`Vitalik持仓: ${ethers.formatEther(balanceDAI)}\n`)
}

main()

可以看到,用两种方法创建的合约实例都能成功与链上交互。Vitalik的钱包里有0.05 WETH555508 DAI,见下图。

成功读取VitalikWETH和DAI持仓

说明 我们可以通过以太坊浏览器 验证Vitalik钱包里的WETH余额, 是否与通过Contract读取的一致。 通过ENS 查到Vitalik钱包地址是0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045,然后通过合约方法balanceOf得到余额正好是0.05 WETH, 结论是一致! VitalikWETH余额

总结

这一讲,我们介绍了ethers中的Contract合约类,并创建了WETHDAI的只读Contract实例,成功读取了Vitalik这两个币的持仓。