lemooljiang avatar

ethers.js与合约交互及事件机制 / 学习智能合约#66

lemooljiang

Published: 20 Nov 2023 › Updated: 20 Nov 2023

ethers.js与合约交互及事件机制 / 学习智能合约#66

上次测试了ethers.js与链上的交互功能,这次测试下与合约的交互以及查看事件的机制。这次也是准备打通链上与AI·Joe的功能:充值与NFT。预备着过几天上线新功能。

ethers.jpg

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

与合约交互

交互基础
ethers.js分析

//只读方法 (like view and pure)
import { ethers } from 'ethers'
//const url = "http://127.0.0.1:8545"
// const url = "https://polygon-rpc.com"
const url = "https://rpc-mumbai.maticvigil.com"
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签名 metamask
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)

//合约的set方法, 需要连上钱包来实现
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)

//另一种写法 在创建合约实例时导入钱包
const privateKey = 'bde95xxxxx'
const wallet = new ethers.Wallet(privateKey, provider)
console.log(56, "wallet:", wallet)
const _Contract = new ethers.Contract(contractAddr, ContractAbi, wallet)

const main = async () => {
    //显示原本的 owner
    let ownerVal = await _Contract.getOwner()
    console.log("原本的 owner:", ownerVal)
    //调用 setOwner 更改 owner
    await _Contract.setOwner("0x503063dD8f114059B09FD5bC953E71fc14a1d672")
    //更改后的 owner
    ownerVal = await _Contract.getOwner()
    console.log("更改后的 owner:", ownerVal)
}
main()

友好的abi

在上一点中,我们使用的 abi 并不是非常友好,咱们编写 abi 还有一种比较简单的 函数签名的方式 编写abi:

const ContractAbi = [
    "function getOwner()view public returns(address)",
]
ok
eg:
const abi = [
    "event Transfer(address indexed from, address indexed to, uint value)",
    "function balanceOf(address account) external view returns (uint256)",
    "function transfer(address recipient, uint256 amount) external returns (bool)"
  ]

读取合约历史事件

查询合约的历史数据通常涉及到查看合约发出的事件(events),queryFilter来查询

import { ethers } from "ethers"

const url = "https://rpc-mumbai.maticvigil.com"
const provider = new ethers.JsonRpcProvider(url)
const abi = [
  "event Transfer(address indexed from, address indexed to, uint value)"
]
const address = '0xaA61b68301278Da4e001d2cF7F8b2202aed6347c'
const contract = new ethers.Contract(address, abi, provider)

// Query the last 1000 blocks for any transfer
let filter = contract.filters.Transfer
let events = await contract.queryFilter(filter, -1000) 
//也可以这样写
// const height = await provider.getBlockNumber()
// const events = await contract.queryFilter('Transfer', height - 1000, height)
console.log(899, "events", events)
//
[
  EventLog {
    provider: JsonRpcProvider {},
    transactionHash: '0x3ca891c7df6ce814e7a418bf1b6985ff88ec2087f540665c752a1916e0982e86',
    blockHash: '0xd8b47357bfcf1ae0185e458d393a1a8ba9a19999aa7c16c719edaadc30ad0419',
    blockNumber: 42621522,
    removed: false,
    address: '0xaA61b68301278Da4e001d2cF7F8b2202aed6347c',
    data: '0x00000000000000000000000000000000000000000000000ae2a8e81db2700000',
    topics: [
      '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
      '0x000000000000000000000000654efb5135e61f3db91dd69d239c2e2812d73604',
      '0x000000000000000000000000469d135bfdde122a198b978d1a85f05100217246'
    ],
    index: 83,
    transactionIndex: 36,
    interface: Interface {
      fragments: [Array],
      deploy: [ConstructorFragment],
      fallback: null,
      receive: false
    },
    fragment: EventFragment {
      type: 'event',
      inputs: [Array],
      name: 'Transfer',
      anonymous: false
    },
    args: Result(3) [
      '0x654Efb5135E61f3Db91dd69d239c2E2812D73604',
      '0x469D135bFdDe122a198B978d1A85f05100217246',
      200800000000000000000n
    ]
  }
]

获取历史日志

getLogs方法获取历史日志

let contractEnsName = '0xaA61b68301278Da4e001d2cF7F8b2202aed6347c'

let topic = ethers.id("Transfer(address,address,uint256)")
console.log(123, topic)
let filter = {
  address: contractEnsName,
  fromBlock: -600,
  toBlock: 'latest',
  topics: [ topic ]
}

let result = await provider.getLogs(filter)
console.log(6663, result)
//
[  Log {
    provider: JsonRpcProvider {},
    transactionHash: '0x8736cd74cb13488df6b49899cd8833206e003c37f02560a92c0ac9495c7155c5',
    blockHash: '0x5e163f0a62cdc8c858a4aaf2ba6cf471c9abf074fc887d611db64a5005fa8a18',
    blockNumber: 42625293,
    removed: false,
    address: '0xaA61b68301278Da4e001d2cF7F8b2202aed6347c',
    data: '0x00000000000000000000000000000000000000000000000029a2241af62c0000',
    topics: [
      '0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef',
      '0x0000000000000000000000003b2dbd900e9b23e94270ade010616b9a28293a87',
      '0x000000000000000000000000032f93fae3866af7e86b8022c8ec33b60965de82'
    ],
    index: 21,
    transactionIndex: 4
  }
]


使
 The Graph
使

事件监听

监听合约事件

async function main(){
    const abi = [
         "event Transfer(address indexed from, address indexed to, uint value)"
        ]

    const address = '0xaA61b68301278Da4e001d2cF7F8b2202aed6347c'
        const contract = new ethers.Contract(address, abi, provider)

    // Begin listening for any Transfer event
    contract.on("Transfer", (from, to, _amount, event) => {
      const amount = ethers.formatEther(_amount)
      console.log(666, `${ from } => ${ to }: ${ amount }`);

      // The `event.log` has the entire EventLog

      // Optionally, stop listening
      event.removeListener()
    })

    /*
    // Same as above
    contract.on(contract.filters.Transfer, (from, to, amount, event) => {
      // See above
    })

    // Listen for any Transfer to "ethers.eth"
    filter = contract.filters.Transfer("ethers.eth")
    contract.on(filter, (from, to, amount, event) => {
      // `to` will always be equal to the address of "ethers.eth"
    })

    // Listen for any event, whether it is present in the ABI
    // or not. Since unknown events can be picked up, the
    // parameters are not destructed.
    contract.on("*", (event) => {
      // The `event.log` has the entire EventLog
    })
    */

}
main()

Leave ethers.js与合约交互及事件机制 / 学习智能合约#66 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