Ethers 101

1. Hello Vitalik
2. Provider
3. Read Contract Information
4. Send ETH
5. Contract Interaction
6. Deploy Contract
7. Retrieve Events
8. Contract Listeners
9. Event Filtering
10. BigInt and Unit Conversion
.
读取合约信息

我最近在重新学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和交易transaction,并可以获得交易的结果和事件。以太坊强大的地方正是合约,所以对于合约的操作要熟练掌握。

创建Contract变量

只读和可读写Contract

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

  • 只读Contract:参数分别是合约地址,合约abi和provider变量(只读)。
const contract = new ethers.Contract(`address`, `abi`, `provider`);
  • 可读写Contract:参数分别是合约地址,合约abi和signer变量。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个参数,分别是合约地址,合约abi和provider变量。合约地址可以在网上查到,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 signature和event 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. 读取WETH和DAI的链上信息

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

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 WETH及555508 DAI,见下图。

成功读取VitalikWETH和DAI持仓

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

VitalikWETH余额

总结

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

上一章下一章