网页前端只能将数据展示给用户,如果想实现更加复杂的功能,就必须涉及到与智能合约的交互。又因为智能合约是部署在区块链上的,所以智能合约的运行并不是本地进行的,而是远程。因此,我们就需要一套工具来让我们的前端和智能合约进行数据通信。这里我们采用 TypeScript 和 ethers.js 进行,包管理器用的是 yarn

安装 ethers.jsfs-extra

安装其实很简单,只需要敲几个命令即可。这里,我们至少需要安装 ethersfs-extra 两个库,ethers 是用于和智能合约进行交互的,fs-extra 则是用于读取 Contract ABI 的(这个 ABI 会在后续创建 ethers.Contract 对象并与之交互时用到)

$
$
$

如果是 Typescript 的话,需要同时安装 fs-extra@types/fs-extra 两个库,前者是库的本体,后者只提供了 Type Annotation.

如何使用 TypeScript 和 Solidity 合约进行交互?

我们首先编译 Solidity Smart Contract. 我们先安装 solc

$

然后用 solc 命令编译合约. 我们假设合约都放在 src/ 目录下,把编译产物输出到 build/ 目录下

$

.bin 是二进制文件;.abi 其实是 .json 文件,里面记录的是智能合约的所有方法以及其参数列表、成员变量等等信息. 我们需要用文件 IO 读取 .abi 文件.

除了 Contract 自身的信息之外,我们还需要直到 Contract 部署在哪儿,即 (1) 合约地址 (2) RPC Provider. 这两个信息怎么看呢?对于本地用 anvil 的测试链,anvil 会直接输出 RPC Provider 和 Contract Address.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 导入 ethers.js
import { ethers } from "ethers";
// 导入 fs 模块,用于读取 ABI
import fs from "fs-extra";

// 读取 ABI
const abi = fs.readFileSync("build/xxxxx.abi", "utf-8");
// 获取合约部署在哪一条链上 (anvil 默认部署在 localhost:8545 上)
const provider = new ethers.JsonRpcProvider("http://127.0.0.1:8545");
// 如果需要改变 Contract 的内部变量,那么就需要获取 signer
const signer = await provider.getSigner();
// 获取合约地址(不是合约所在区块的地址)
const address = "0x5.........";

// 创建 TypeScript 的 Contract 对象,用以交互
const contract = new ethers.Contract(address, abi, signer);
// 如果不需要修改: const contract = new ethers.Contract(address, abi, provider);