走进web3的世界从Ethers开始(三)

350 阅读4分钟

最近在学习web3所以根据自己的学习内容每天写一篇笔记出来,算是联系也算是巩固! 希望自己早日可以找到web3的工作。 image.png

在我看来ethers就是传统开发中的axios,他使得我们可以非常快速简单的访问区块链上的信息。那么ethers究竟为我们提供了哪些功能呢?让我们来一起学习一下吧!

书接上文我们继续来学习ethers中的Contract类:

今天我们来学习可写的Contract合约变量,并利用它与测试网的WETH合约交互。

创建可写Contract变量

声明可写的Contract变量的规则:

const contract = new ethers.Contract(address, abi, signer)

其中address为合约地址,abi是合约的abi接口,signerwallet对象。注意,这里你需要提供signer,而在声明可读合约时你只需要提供provider。为什么要这样做呢?因为写入合约的操作会涉及到gas和转账等操作,所以我们需要signer对象来实现。

我们也可以利用下面的方法,将可读合约转换为可写合约:

const contract2 = contract.connect(signer)

合约交互

我们在之前介绍了读取合约信息。它不需要gas。这里我们介绍写入合约信息,我们需要构建交易,并且支付gas。该交易将由整个网络上的每个节点以及矿工验证,并改变区块链状态。

我们可以用下面的方法进行合约交互:

// 发送交易
const tx = await contract.METHOD_NAME(args [, overrides])
// 等待链上确认交易
await tx.wait() 

其中METHOD_NAME为调用的函数名,args为函数参数,[, overrides]是可以选择传入的数据,包括:

  • gasPrice:gas价格
  • gasLimit:gas上限
  • value:调用时传入的ether(单位是wei)
  • nonce:nonce

注意:  此方法不能获取合约运行的返回值,如有需要,要使用Solidity事件记录,然后利用交易收据去查询。

接下来我们来用具体的代码去实现一个例子吧。

例子:与sepolia测试网WETH合约交互

在sepolia测试网区块链浏览器上搜索到WETH合约的地址为0xb16F35c0Ae2912430DAc15764477E179D9B9EbEa image.png

My Web3文件夹中创建05_WriteContract文件夹,并在其中创建文件WriteContract.js

image.png

// 声明只可写合约的规则:
// const contract = new ethers.Contract(address, abi, signer);
// 参数分别为合约地址`address`,合约ABI `abi`,Signer变量`signer`
import { ethers } from "ethers";
// 利用Alchemy的rpc节点连接以太坊测试网络
const ALCHEMY_SEPOLIA_URL = '你申请的Connect to Alchemy URL';
const provider = new ethers.JsonRpcProvider(ALCHEMY_SEPOLIA_URL);

// 利用私钥和provider创建wallet对象
const privateKey = '你的privateKey'
const wallet = new ethers.Wallet(privateKey, provider)

// WETH的ABI
const abiWETH = [
    "function balanceOf(address) public view returns(uint)",
    "function deposit() public payable",
    "function transfer(address, uint) public returns (bool)",
    "function withdraw(uint) public",
];
// WETH合约地址(sepolia测试网)
const addressWETH = '0xb16F35c0Ae2912430DAc15764477E179D9B9EbEa'
// WETH Contract

// 声明可写合约
const contractWETH = new ethers.Contract(addressWETH, abiWETH, wallet)
// 也可以声明一个只读合约,再用connect(wallet)函数转换成可写合约。
// const contractWETH = new ethers.Contract(addressWETH, abiWETH, provider)
// contractWETH.connect(wallet)
const deposit = async () => {

    const address = await wallet.getAddress()
    // 1. 读取WETH合约的链上信息(WETH abi)
    console.log("\n1. 读取WETH余额")
    const balanceWETH = await contractWETH.balanceOf(address)
    console.log(`存款前WETH持仓: ${ethers.formatEther(balanceWETH)}\n`)
    //读取钱包内ETH余额
    const balanceETH = await provider.getBalance(wallet)

    // 如果钱包ETH足够
    if (ethers.formatEther(balanceETH) > 0.001) {
        // 2. 调用deposit()函数,将0.001 ETH转为WETH
        console.log("\n2. 调用deposit()函数,存入0.001 ETH")
        // 发起交易
        const tx = await contractWETH.deposit({ value: ethers.parseEther("0.001") })
        // 等待交易上链
        await tx.wait()
        console.log(`交易详情:`)
        console.log(tx)
        const balanceWETH_deposit = await contractWETH.balanceOf(address)
        console.log(`存款后WETH持仓: ${ethers.formatEther(balanceWETH_deposit)}\n`)
    } else {
        // 如果ETH不足
        console.log("ETH不足,去水龙头领一些sepolia ETH")
        console.log("https://testnet.help/en/ethfaucet/sepolia#log 领取地址")
    }
}

// deposit()


const withdraw = async () => {
    const address = await wallet.getAddress()
    // 1. 读取WETH合约的链上信息(WETH abi)
    console.log("\n1. 读取WETH余额")
    const balanceWETH = await contractWETH.balanceOf(address)
    console.log(`取款前WETH持仓: ${ethers.formatEther(balanceWETH)}\n`)
    // 2. 读取ETH数量
    console.log(`读取ETH数量: ${ethers.formatEther(await provider.getBalance(wallet))} ETH`)
    // 3. 调用withdraw()函数,将0.001 WETH转为ETH
    console.log("\n2. 调用withdraw()函数,取出0.001 WETH")
    // 发起交易
    const tx = await contractWETH.withdraw(ethers.parseEther("0.001"))
    // 等待交易上链
    await tx.wait()
    console.log(`交易详情:`)
    console.log(tx)
    const balanceWETH_withdraw = await contractWETH.balanceOf(address)
    console.log(`取款后的WETH持仓: ${ethers.formatEther(balanceWETH_withdraw)}\n`)
    // 4. 再次读取ETH数量
    console.log(`再次读取ETH数量: ${ethers.formatEther(await provider.getBalance(wallet))} ETH`)
}

// withdraw()

我们在文件中设计了两个函数,分别为depositwithdraw函数,其中deposit为存款函数,将我们的ETH存入WETH合约以换取WETH代币。withdraw函数是将我们的WETH代币取出置换回ETH币。

废话不多说一起看看两个函数的执行结果吧,我们先来执行一下deposit函数:

image.png

这样我们就成功存入了0.001枚ETH换取了一枚WETH到我们的钱包中。也可以在MetaMask进行查看验证。

image.png

那接下来我不想要这0.001枚WETH了,那就让我们执行withdraw函数吧。

image.png

我们通过执行打印的log可以看到我们的代币变化,同样我们仍然可以去MetaMask中进行查看(因为需要消耗gas所以我们前后的ETH数量是有所差别的)

image.png

学到这里我们就可以通过代码实现一个最基础的与合约交互的方法啦,是不是有点跃跃欲试呢?赶紧动手试一试吧!