<https://docs.ethers.org/v6/>

Ethers.js 是一个使用Typescript编写的库,用于构建去中心化应用程序(DApps)的前端,或者与以太坊网络进行交互。它抽象了许多复杂性,使开发人员能够简单直观地构建DApp。

使用 ethers.js 的好处
1. 轻量。v6.12.0 缩小后仅为 394.8 KB。
2. 使用Typescript编写,确保类型的安全,并在编译时识别问题,而非等到运行时。
3. 网络连接和私钥由Provider和Wallet类分别管理,使其更加安全。
4. 它与 Node.js 和现代 Web 浏览器兼容,允许开发人员在各种环境中使用它。
5. 其API使用简单易懂。
6. 对以太坊名称服务(ENS)的本地支持。
7. 它不断积极维护和更新。

主要的类
1. 合约 (Contracts)
它提供了与智能合约交互的实用程序,包括用于部署合约、实例化合约、调用合约方法和监听合约事件的类。
2. 签名者 (Signer)
它处理私钥,对消息和交易进行签名,发送已签名交易,并在此过程中修改区块状态。
3. 钱包 (Wallets)
它提供了安全管理帐户和私钥的功能。它包括从助记词短语生成钱包、从私钥导入钱包、与硬件钱包交互以及签名交易的类。它是Signer的子类。
4. 提供者 (Providers)
它提供了连接到以太坊网络并从区块链中检索数据的功能,包括用于HTTP、WebSockets等的提供者。
5. 实用程序 (Utilities)
它提供了将令牌单位从人类友好的格式转换为区块链兼容格式的功能,例如从ETH到Wei,反之亦然。它还处理各种数据种类的编码和解码,以及一些加密操作。

# 创建项目
步骤 1:创建一个npm项目
npm init
步骤 2:安装 ethers.js
npm install ethers
步骤 3:配置类型为模块
"type": "module"
步骤 4:设置您的开发环境
步骤 5:启动您的项目

# 提供者类 (Provider Class)
ethers.js 的 Providers 类提供了连接到以太坊网络的抽象。它只能从区块链中读取信息,不处理用户的私钥,因此使用起来更安全。
ethers.getDefaultProvider()
ethers.JsonRpcProvider

获取 URL
以下是几种获取节点 URL 的方法:
1. Infura: Infura 是一个流行的以太坊节点提供者,提供免费和付费计划。您可以在 Infura 上注册账户并获取要连接到的以太坊网络的 URL。URL 通常如下所示:<https://mainnet.infura.io/v3/YOUR_PROJECT_ID>
2. Alchemy: 您也可以获取要连接到的节点的 URL,URL 通常如下所示: <https://eth-mainnet.alchemyapi.io/v2/YOUR_API_KEY>
3. 本地节点 (Ganache, Geth, etc.): 您还可以使用 Ganache 或 Geth 等工具运行本地节点。默认的 URL 如下所示: <http://localhost:8545>
4. 公共以太坊网络:对于像主网、Ropsten、Rinkeby 等公共以太坊网络,您可以找到提供免费访问或注册付费服务的公共节点提供者。

# 从区块链获取信息
以下 Provider 类中一些常用的方法。
getBalance()
获取账户的余额,单位为 wei。
getNetwork()
获取有关网络的信息,例如网络名称、链ID等。
getBlockNumber()
获取当前区块号。
getTransactionCount()
返回特定地址的交易数量,包括收入和支出的交易。
getFeeData()
获取与费用相关的数据,如当前的 gas 价格和估计的 gas 限制。
getBlock()
检索有关特定区块的详细信息,包括哈希、时间戳、交易等。
getCode()
获取部署智能合约的字节码。

# 合约类 (Contract Class)
以太坊区块链的强大之处在于其智能合约。在 ethers.js 中,Contracts 类是部署在以太坊网络上的合约的抽象。它可以获取交易结果和事件,并与智能合约进行交互。
Contracts 对象可以是只读的或状态更改的。
只读合约
它接受合约地址、合约 ABI 和提供者作为参数。
const contract = new ethers.Contract(`address`, `abi`, `provider`);
状态更改的合约
它接受合约地址、合约 ABI 和签名者作为参数。
const contract = new ethers.Contract(`address`, `abi`, `signer`);

# 获取 ABI
在我们编写合约调用之前,让我们先看一下应用二进制接口(ABI)。ABI 定义了软件组件在二进制级别上如何通信和交互。它指定了数据结构、函数签名以及编码和解码信息的约定。

获取智能合约的 ABI 有几种方法,我们将在这里讨论 3 种方法:
1. 区块链浏览器:例如,可以在 Etherscan 中找到合约 ABI,通过合约地址搜索,然后转到“合约”选项卡,并搜索“合约 ABI”。
2. 标准库:许多智能合约使用标准的第三方库或框架,如 OpenZeppelin,它们提供了预先构建的合约及其相应的 ABI。您可以在它们的文档中找到。
3. 开发工具:像 Truffle、Hardhat 或 Remix 这样的工具通常提供了从部署的合约中提取 ABI 的实用工具。

# ABI 对象

直接输入智能合约的 ABI
输入函数签名

# 签名者 (Signers) 和钱包 (Wallets) 类
在 ethers.js 中另一个重要的类是 Signer 及其派生类 Wallets。它们的功能是签署消息和交易,并将已签署的交易发送到网络。当交易成功包含在区块链中时,它会改变区块链的状态。

## 签名着 (Signers)
Signers 类不仅可以代表 EOA,还可以代表其他类型的签名者,如合约钱包或外部钱包提供者,例如 MetaMask。由于它是一个抽象类,因此不能直接实例化。必须通过 Wallets 来完成的。
## 钱包(Wallets)
Wallets 是 Signers 类的具体实现。它简化了与以太坊区块链的交互。它直接访问私钥管理,并适用于应用程序内部使用。

# 连接钱包
使用随机私钥创建新钱包
使用私钥导入现有账户
使用助记词导入现有账户
从 JSON 文件导入现有账户

# 与现有合约交互
加载现有合约
调用合约函数

# 格式化
ethers.parseEther
将 ETH 转换为 Wei,即 ETH 的最小单位,也是以太坊区块链中使用的最小单位。
parseEther('1')converts 1 ETH to 1,000,000,000,000,000,000 Wei.

ethers.formatEther
将 ETH 转换为 Wei,即 ETH 的最小单位,也是以太坊区块链中使用的最小单位。
parseEther('1')converts 1 ETH to 1,000,000,000,000,000,000 Wei.

ethers.parseUnits
将 Wei 转换为 ETH,以便更容易阅读的格式。
formatEther('1000000000000000000')converts 1,000,000,000,000,000,000 Wei to 1 Ether.

ethers.formatUnits
将较大的单位转换为较小的单位。例如,从 1 ETH 转换为 1,000,000,000 Gwei。parseUnits('1', 9)将 1 ETH 转换为具有 9 位小数的 Gwei。
它将任何令牌单位转换为具有指定小数精度的最小单位,该小数精度在第二个参数中声明。

Converts smaller units to larger units. E.g. from Gwei to ETH.
单位从具有指定小数精度的最小单位转换为较大单位,该小数精度在第二个参数中声明。

# 编码和解码
所有发送到以太坊区块链的数据都需要进行相应的编码。
1. 数据压缩和效率:区块链网络越大,安全性越高。因此,将任何数据轻量化以有效地在大型网络中传输数据非常重要。这也有助于减少存储空间。
2. 数据完整性和安全性:将数据编码为特定标准可确保数据正确格式化和清晰解释,从而减少错误、漏洞和不一致性

hexlify() 
将值转换为其十六进制表示形式。

encodeRlp()
使用递归长度前缀(RLP)编码对数据进行编码,常用于编码交易数据和参数。

toUtf8Bytes()
将 UTF-8 编码的字符串转换为其对应的字节。由于以太坊智能合约以字节形式存储和操作数据,因此需要将字符串转换为字节。

# 加密操作
密码学是区块链的重要组成部分,原因如下:
1. 安全性:密码学确保了区块链上的交易和数据的完整性和真实性。它防止了未经授权的访问,并保护了敏感信息。
2. 身份验证:密码操作使用户能够安全地验证其身份并授权交易,而无需中央机构或中介。
3. 数据隐私:加密是一种保护在区块链上传输和存储的敏感数据隐私的密码方法。
4. 不可变的记录:哈希是一种保证在区块链上传输的数据保持不可篡改的密码方法。

keccak256()
基于 Keccak-256 算法,从输入数据生成一个 256 位的哈希值。
const hash = ethers.keccak256("Hello, world!"); 

sha256()
类似于 keccak256(),它基于 SHA-256 算法从输入数据生成一个 256 位的哈希值。

# 发送交易
只有签名的交易才能被广播到内存池,并且每个被接受到区块链上的交易都将改变区块链的状态。在发送交易之前,让我们构建交易并对其进行签名。

# 构建交易
构建交易需要一些参数:接收者的地址、要转移的值/物品、gas limit 和 gas price。

# 签署交易
当所有信息就绪时,我们可以对交易进行签名。回顾一下:Wallet 管理私钥,因此参与签署交易。这个过程生成一个数字签名,证明了交易的真实性和授权性。

# 广播交易
回顾一下:Provider 连接到网络中的一个节点。我们还可以获取广播的交易哈希以供参考,特别是用于检查交易是否已被挖掘,并一旦被挖掘,从区块链中检索其详细信息。

# 等待确认
以太坊平均每 12 秒形成一个新的区块,但不是立即。因此,我们需要等待交易被挖掘。

广播的交易可能由于各种原因而未被包含在区块中。常见原因包括:
1. 内存池中的交易太多,而较低 gas fee 的交易将被那些具有较高费用的交易挤出。它们可能稍后被包含在区块中。
2. gasLimit 设定过低。
3. 如果发送方试图花费发送方没有的硬币,或数字签名不正确,导致交易被拒绝。
4. 某些矿工或节点可能会审查某些交易。