lemooljiang avatar

ethers.js链上交互指南 / 学习智能合约#65

lemooljiang

Published: 26 Oct 2023 › Updated: 26 Oct 2023

ethers.js链上交互指南 / 学习智能合约#65

这些天想升级Dapp的时候却发现web3.js包用不了!web3.js一直以来是又大又难装,这下彻底完犊了,用不了了。这时只能启用备用方案:ethers.js

ethers.jpg

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

ethers.js更新的挺快,这就6.8的版本啰!

简单对比了下,ethers.js大约是18M, web3.js却有近57M!ethers.js很是小巧灵活。测试了一些写法,感觉还是很丝滑的。而且功能也很全面,爱了!

下载与资源

ethers |
ethers-github |
中文文档 |

安装

npm install ethers --save 
// "ethers": "^6.8.0"   18.3M
// cnpm install ethers --save 
// yarn add ethers

Gas

一经创建,每笔交易都收取一定数量的 gas ,目的是限制执行交易所需要的工作量和为交易支付手续费。EVM 执行交易时,gas 将按特定规则逐渐耗尽。

gas price 是交易发送者设置的一个值,发送者账户需要预付的手续费= gasPrice * gas 。如果交易执行后还有剩余, gas 会原路返还。

创建providers

ethers是一套和以太坊节点进行通信的API,是对JSON-RPC的封装。如果我们需要基于以太坊来开发去中心化应用,就需要通过ethers来获取节点状态,获取账号信息,调用合约、监听合约事件等等。

智能合约是运行在节点提供的虚拟机上,因此调用智能合约也需要像节点发送请求。

import { ethers } from 'ethers'
// const ethers = require('ethers')

//使用本地节点或是远程节点
const url = "http://127.0.0.1:8545"
//"http://localhost:8545" 会报错
// const url = "https://rpc-mumbai.maticvigil.com"
// const url = "https://rpc.ftm.tools/"
const provider = new ethers.JsonRpcProvider(url)
//交易签名
const signer = await provider.getSigner() //默认地址,一般是第一个
//const signer = await provider.getSigner("0x025C4AB61A50Ce391E9F3cd88a858E5C5ADABaF1") //可以这样指定

//metamask中获取
provider = new ethers.BrowserProvider(window.ethereum)

基本使用

// Look up the current block number
await provider.getBlockNumber()
// 16383845

//获取一个地址或ENS的余额
let addr = "0xf9eFdD67e2C46a8086aed666ea8e294986AB285C"
let balance = await provider.getBalance(addr)
// 100000000000000000000n

//eth转成wei
ethers.parseEther("1.2")
//1200000000000000000n

//wei转成 eth
ethers.formatEther('23')
// 0.000000000000000023


//发送交易
const option = {
    to:toAccount,
    value: 1500000000,  //wei
    gas: gas,
    gasPrice: gasPrice
}
eg:
const tx = await signer.sendTransaction({
    to: "0xf33B812142b8a008cD98ED889605869B31393849",
    value: ethers.parseEther("1.0")
  })
const receipt = await tx.wait()
console.log(899, receipt) 
/*
TransactionReceipt {
  provider: JsonRpcProvider {},
  to: '0xf33B812142b8a008cD98ED889605869B31393849',
  from: '0xf9eFdD67e2C46a8086aed666ea8e294986AB285C',
  contractAddress: null,
  hash: '0xafac68a6a871424bf2aa4da66b7aed38c379bd335e56f8bfecdea680febac5ed',
  index: 0,
  blockHash: '0xb5e876eae0264cdfbbb7e8d0e3676ed31abc6121d78fc9080498fea3bdafa3d2',
  blockNumber: 1,
  logsBloom: '0x0000000....00',
  gasUsed: 21000n,
  cumulativeGasUsed: 21000n,
  gasPrice: 20000000000n,
  type: 0,
  status: 1,
  root: undefined
}
*/

常用方法

1. 
//eth转成wei
ethers.parseEther("1.2")
//1200000000000000000n
//wei转成 eth
ethers.formatEther('23')
// 0.000000000000000023

//另外一种转换方法
ethers.parseUnits("1.3", 18) // 乘以10**18
//1300000000000000000n
ethers.formatUnits("1300000000000000000", 18) // 除以10**18
//1.3

2. gasLimit 
signer.estimateGas(tx)
 gas , 30000gas

3. GasPrice
await provider.getFeeData() //获取当前gas价格
/*
FeeData {
  gasPrice: 20000000000n,
  maxFeePerGas: null,
  maxPriorityFeePerGas: null
}*/

4. 
await provider.getBlockNumber()
//2655567

钱包功能

手册
新帐户

import { ethers } from 'ethers'
import fs from 'fs'

//直接生成私钥和地址
let lbcWallet = ethers.Wallet.createRandom()
lbcWallet.address
// "0x863e27dbD608649d08c69F83ccA51b045721f318"
lbcWallet.privateKey
// "0x8bc29xxxxxxx"

//随机数生成钱包
let random = ethers.randomBytes(32) 
console.log(563, random)
let privateKey = Buffer.from(random).toString('hex')   //转成16进制
console.log(112, privateKey) 
let wallet = new ethers.Wallet(privateKey)
console.log("账号地址: " + wallet.address, wallet)

//生成随机助记词并创建钱包
let mnemonic = ethers.Mnemonic.fromEntropy(ethers.randomBytes(16))
// let mnemonic = ethers.Mnemonic.fromEntropy(ethers.randomBytes(16), "jxxxx")  第二个参数是密码
console.log(1323, mnemonic)
var path = "m/44'/60'/0'/0/0"
// 通过助记词创建钱包
let wallet = ethers.HDNodeWallet.fromMnemonic(mnemonic, path) 
console.log("账号地址: " + wallet.address, wallet)

//根据助记词找回钱包信息
let monic = "dinosaur tape orbit chronic private ....."
let mnemonic = ethers.Wallet.fromPhrase(monic)
console.log(566, mnemonic)
let privateKey = mnemonic.privateKey
console.log("钱包私钥:",privateKey)

//根据私钥找回钱包地址
let wallet = new ethers.Wallet(privateKey)
//钱包地址
let address = wallet.address
console.log(156, address)

//生成json钱包文件
let main = async function (){
  let random = ethers.randomBytes(32) 
  let privateKey = Buffer.from(random).toString('hex')  //转成16进制
  let wallet = new ethers.Wallet(privateKey)
  let password = "xxxxx"
  let res = await wallet.encrypt(password)
  console.log(156, res)
  let d = new Date()
  let time = d.getTime()
  let path = './keystore/' + time + '-' + wallet.address
  fs.writeFileSync(path, res)
}

//json文件找回钱包信息
let main2 = async function (){
  let res = fs.readFileSync('./keystore/16983xxxxxxxxxxxB2c6', "utf8")
  let password = "xxxxxx"
  let wallet = await ethers.Wallet.fromEncryptedJson(res, password)
  console.log("Address: " + wallet.address, wallet,"privateKey:", wallet.privateKey)
}

与合约交互

//只读方法 (like view and pure)
import { ethers } from 'ethers'
const url = "http://127.0.0.1:8545"
const provider = new ethers.JsonRpcProvider(url)
let abi = [
    "function str() view returns (string)",
    "function set(uint x)",
    "function get()view returns (uint)"
  ]
//这里的abi相当于接口
// 也可以使用合约的编译abi: import Storage from '@/static/Storage.json' -> Storage.abi
let contractAddr = "0x600a00aE84b896edd9F2732565cf2195d032315E"
let contract = new ethers.Contract(contractAddr, abi, provider)
let str = await contract.get()
console.log(256, str)

//合约的所有方法, signer签名
const url = "http://127.0.0.1:8545"
const contractAddr = "0x600a00aE84b896edd9F2732565cf2195d032315E"
const provider = new ethers.JsonRpcProvider(url)
const signer = await provider.getSigner()
const contract = new ethers.Contract( contractAddr,  Storage.abi,  signer)
console.log(56, "signer:", signer)
const option = { 
}
const tx = await contract.set(996, option)
await tx.wait()
console.log(669, "singen res:", tx)

//合约的所有方法, 也可以连上钱包来实现
import Storage from '@/static/Storage.json'
const url = "http://127.0.0.1:8545"
const contractAddr = "0x600a00aE84b896edd9F2732565cf2195d032315E"
const provider = new ethers.JsonRpcProvider(url)
const contract = new ethers.Contract(contractAddr, Storage.abi, provider)
const PRIVATE_KEY = "0x182xxxxxxxxx"
const wallet = new ethers.Wallet(PRIVATE_KEY, provider)
console.log(56, "wallet:", wallet)
const nonce = await provider.getTransactionCount(wallet.address)
console.log(58, "nonce:", nonce)
const StorageConnected = contract.connect(wallet)
const option = {
    nonce
}
const tx = await StorageConnected.set(86394, option)
await tx.wait()
console.log(669, "res:", tx)

ethers的体验相当不错,功能齐全,它的转正也是情理之中啰。

Leave ethers.js链上交互指南 / 学习智能合约#65 to:

Written by

Designer , Poet , Technology enthusiasts

Read more #smartcontract posts


Best Posts From lemooljiang

We have not curated any of lemooljiang's posts yet. But you can encourage our curation team to review posts by visiting them regularly and by referring other readers. Because we give priority to frequently read content.

More Posts From lemooljiang