title | tags | ||||||
---|---|---|---|---|---|---|---|
13. 编码calldata |
|
我最近在重新学ethers.js
,巩固一下细节,也写一个WTF Ethers极简入门
,供小白们使用。
WTF Academy社群: 官网 wtf.academy | WTF Solidity教程 | discord | 微信群申请
所有代码和教程开源在github: github.com/WTFAcademy/WTFEthers
这一讲,我们将介绍ethers.js
中的接口类,并利用它编码calldata
。
ethers.js
的接口类抽象了与以太坊网络上的合约交互所需的ABI
编码和解码。ABI
(Application Binary Interface)与API
类似,是一格式,用于对合约可以处理的各种类型的数据进行编码,以便它们可以交互。更多内容见WTF Solidity教程第27讲 ABI编码。
我们可以利用abi
生成或者直接从合约中获取interface
变量:
// 利用abi生成
const interface = ethers.Interface(abi)
// 直接从contract中获取
const interface2 = contract.interface
接口类封装了一些编码解码的方法。与一些特殊的合约交互时(比如代理合约),你需要编码参数、解码返回值:
注意:相关函数必须包含在abi
中。
-
getSighash()
:获取函数选择器(function selector),参数为函数名或函数签名。interface.getSighash("balanceOf"); // '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef'
-
encodeDeploy()
:编码构造器的参数,然后可以附在合约字节码的后面。interface.encodeDeploy("Wrapped ETH", "WETH");
-
encodeFunctionData()
:编码函数的calldata
。interface.encodeFunctionData("balanceOf", ["0xc778417e063141139fce010982780140aa0cd5ab"]);
-
decodeFunctionResult()
:解码函数的返回值。interface.decodeFunctionResult("balanceOf", resultData)
这里,我们利用接口类编码calldata
的方法,重复第5讲中与测试网WETH
合约交互的例子。
-
创建
provider
,wallet
变量。//准备 alchemy API 可以参考https://github.com/AmazingAng/WTFSolidity/blob/main/Topics/Tools/TOOL04_Alchemy/readme.md const ALCHEMY_GOERLI_URL = 'https://eth-rinkeby.alchemyapi.io/v2/GlaeWuylnNM3uuOo-SAwJxuwTdqHaY5l'; const provider = new ethers.JsonRpcProvider(ALCHEMY_GOERLI_URL); // 利用私钥和provider创建wallet对象 const privateKey = '0x227dbb8586117d55284e26620bc76534dfbd2394be34cf4a09cb775d593b6f2b' const wallet = new ethers.Wallet(privateKey, provider)
-
创建
WETH
合约实例// WETH的ABI const abiWETH = [ "function balanceOf(address) public view returns(uint)", "function deposit() public payable", ]; // WETH合约地址(Goerli测试网) const addressWETH = '0xb4fbf271143f4fbf7b91a5ded31805e42b2208d6' // 声明WETH合约 const contractWETH = new ethers.Contract(addressWETH, abiWETH, wallet)
-
调用
balanceOf()
函数,读取钱包地址address
的WETH
余额。const address = await wallet.getAddress() // 1. 读取WETH合约的链上信息(WETH abi) console.log("\n1. 读取WETH余额") // 编码calldata const param1 = contractWETH.interface.encodeFunctionData( "balanceOf", [address] ); console.log(`编码结果: ${param1}`) // 创建交易 const tx1 = { to: addressWETH, data: param1 } // 发起交易,可读操作(view/pure)可以用 provider.call(tx) const balanceWETH = await provider.call(tx1) console.log(`存款前WETH持仓: ${ethers.formatEther(balanceWETH)}\n`)
-
调用
deposit()
函数,将0.001 ETH
转换为0.001 WETH
,打印交易详情和余额。可以看到余额变化。// 编码calldata const param2 = contractWETH.interface.encodeFunctionData( "deposit" ); console.log(`编码结果: ${param2}`) // 创建交易 const tx2 = { to: addressWETH, data: param2, value: ethers.parseEther("0.001")} // 发起交易,写入操作需要 wallet.sendTransaction(tx) const receipt1 = await wallet.sendTransaction(tx2) // 等待交易上链 await receipt1.wait() console.log(`交易详情:`) console.log(receipt1) const balanceWETH_deposit = await contractWETH.balanceOf(address) console.log(`存款后WETH持仓: ${ethers.formatEther(balanceWETH_deposit)}\n`)
这一讲,我们介绍了ethers.js
中的接口类,并利用它编码calldata
与WETH
合约交互。与一些特殊的合约交互时(比如代理合约),你需要用这类方法编码参数,然后解码返回值。